I do think Julia has serious correctness and maintainability issues, but it’s worth being precise about what exactly is the problem, and what Julia, by contrast, does well.
For example, Julia is pretty good about not introducing blatantly breaking changes. Not perfect, mind you [1, 2], but straight up breaking changes are more rare than in e.g. Python. It’s also unlikely that basic numeric computation is going to break: Julia is quite explicit and careful about these kinds of numerics. So, in that sense, if you write some Julia code doing some computation, you probably don’t have worry.
In that vein, my experience has been that the code I wrote in 2020 still works flawlessly, and the code that Kenta Sato wrote in 2017-ish worked perfectly when I took over maintenance. I generally experience way less spontanous breakage maintaining my Julia code than maintaining my Python code. A very low bar, to be sure, but do note that noone goes around talking about Python like it’s a mess of breakage.
I also think the idea that Julia is full of straight up bugs is wildly overstated. Julia’s libraries are typically much better tested than Python’s and, again, I tend to find less bugs in Julia’s packages than in Python’s; at least for similar levels of popularity. There are bugs, sure, but the idea that bugs are so much more plentiful in Julia that it makes your programs less reliable doesn’t match my experience at all.
That being said, my experience of practical stability is shaped by me being quite careful about writing maintainable code, and Julia doesn’t make that easy:
Until recently, there was no public/private distinction in Julia. That border is still very fuzzy. For example, public functions are regularly discovered never to have been made public, and it’s deeply inconsistent and uncertain what properties of public functions are actually stable. For example, is the precise signature of functions considered stable? What about the return type? What about the exceptions they throw? What about the fields of structs?
More broadly, once you get deep into Julia, at least I have gotten the feeling that everything is built on sand, because very little can actually be relied on, when you look in the details. A core developer may not be able to delete a function, but since typically, very little about a function is documented, there’s hardly any function you can really use with the certainty that it’s covered by API.
Part of this is the behaviour of Julia structs and functions that is severely underspecified and underdocumented. For example, after using Julia for nine years, I have yet to understand what type map returns, and to what extent that is documented. Or understand what the init argument to the reduce functions actually do. Or the principles by which Julia functions handle aliasing arguments. That’s not me being dense - that’s just because there isn’t any consistent behaviour to understand. As a consequence, whenever your use common functions like map in your code you just have to pray that someone doesn’t decide it actually means something different than you assumed.
Then there’s the way the whole runtime works which is also full of sharp edges. There are way, way too many compile time traps, so performance in Julia is always a risky bet. Inference is an opaque compiler detail; it’s unstable and tends to shift under your feet - what was inferred three years ago often isn’t inferred when you run the program again, making the performance profile of your code change over time. You will often feel like runtime performance depends on the compiler, the multithreading system implementation, and the garbage collector, all of which are shifting internals that are difficult to satisfy.
I minor nitpick; Rust slightly older than Julia; both first appeared around 2012, but Julia hit 1.0 in 2018, and Rust in 2015.