> A better catchphrase for Julia might be "The best expressiveness / performance tradeoff you have ever seen".

Man, Jakob just has a way of writing that gets right to the point. Nice post.

My only complaint about the post is that in Python you have many different REPL options. For example, both ipython and bpython are miles ahead of the Julia REPL. I agree though that the Julia default REPL is better than the Python default REPL. I particularly like the shell mode in Julia. You can also make your own modes, like a sql mode or any custom DSL mode.

I have been very critical about Julia in the past, so I'll say some positive things before I complain more :)

- The package management in Julia is god-like. Specifically, there's a whole subset of packages that are just binaries and libraries cross compiled on VMs for Windows / Mac / Linux + x86 / x64 / ARM, and it just works. There's no more trying to compile code on a users computer when trying to install a package, it's beautiful. It is truly a phenomenal piece of engineering, and I cannot praise it enough. Hats off to the core team responsible for this.

- Multithreading is such a joy to use. Compared to any other dynamic GC language, Julia and Go are pretty much up there in terms of usability + features. So much better than Python or R. But while I prefer Julia over Go, I do prefer Rust over Julia.

Now for some of my grievances. I'm a nobody in the Julia community so take my word for what it is worth.

- Optimizing Julia code is a joy. However, learning how to optimize Julia code not straightforward. If you are coming from Python and/or don't have experience thinking about memory, cache lines, references, mutability etc, you have your work cut out for you in terms of learning how to optimize Julia code. In addition to that, there are Julia specific things you need to learn to know how to optimize your code. Do you know what the function barrier paradigm is? No? Too bad, now your codebase is 10x slower and refactoring could take weeks. And that's just the theory of everything you need to learn. There's SO many subtle ways your Julia code can be slow because the compiler wasn't able to "see through your code". And the tooling here is getting better but still has a LOONNNGGG way to go. Statically being able to check and assert for problematic inferences will improve this for me a la JET.jl but right now JET.jl is too slow to run on a large codebase.

- Thinking with Multiple Dispatch (MD) is much like Thinking with Portals. Once you get it, you have this ah-ha moment. But the type system is overloaded in my opinion. You HAVE to use the type system for MD but people also use it for interfaces (AbstractArray for example). I think adding inheritance in the abstract type system was a mistake, and a trait or interface like approach would be way better for this. Maybe something like concrete types for dispatch and abstract types for interfaces? I don't think this will EVER change though, not in Julia 2.0 or 3.0 or later, because it is SO ingrained into the Julia community. I'm not explaining this well here but I've complained about it before in previous comments on HN and am too lazy to go find it and copy paste :)

- There's a number of minor syntax / usability gripes I have that I don't think will ever be fixed as well. I generally think a programming language should incentivize you to "do the right thing", often my making it easier to type. In Julia this framework of thinking exists but isn't applied consistently. It is easier to create a immutable struct than a mutable struct

struct Immutable
x::Int
y::Int
end
# vs
mutable struct Mutable
x::Int
y::Int
end

However, if you want to use it to store user data, if you choose immutable structs, your interface for users is EXTREMELY annoying. For example, if they want to update `x` from `1` to be `2`.

im = Immutable(1, 3)
im = Immutable(2, im.y)

With mutable structs:

m = Mutable(1, 3)
m.x = 2

There's third party packages that make this easier but this should ABSOLUTELY be in Base.

There's similar complaints I have about type names in Julia. I'm incentivized to write `::String` instead of `::AbstractString`, `::Int` instead of `::Integer`. In Julia using `AbstractString` is almost always preferred.
The naming is also quite annoying. Why does `AbstractString` have `Abstract` in the name but `Integer` not, when both of them are abstract types?

I've said this before and I'll say it again. I think Julia core devs should have a usability expert come in and review their whole codebase and workflows and make suggestions. I have no idea how Rust has nailed this so well. In Rust, so many things are just consistent. You can guess what the names or behavior of what you want so often, it's awesome.

TLDR:

If you are thinking of using Julia for a large production codebase, wait 5 more years. I've learnt that the hard way. For personal projects it is amazing though.