326 comments

[ 3.1 ms ] story [ 280 ms ] thread
the language integration/interop could be solved if they migrated to GRAALVM
The things that stick out to me as unwieldy in Julia:

* Not embracing functional style idioms. There's no TCO so writing recursive algorithms from old FP papers is hard. Not an issue per se, just gripe.

* Not having explicit interfaces. I'm sure there's some advanced Julia-fu that I could do to introspect my way to knowing what methods I need, but the very concept of them not being explicit irks me. Again, not an issue per se, but it annoys me.

* There's a complete and total disregard to any notion of a smaller Julia or a Julia more suited for general purpose. Julia seems ripe to benefit from a Ruby&mruby sorta situation, but alas. We need this gigantic blob of dependencies and toolchains and compilers and this and that, to operate this programming language. I don't get it. For the last time, it's not an issue per se, and the language has achieved incredible engagement in many demanding niches, so what do I know anyhow?

There's no TCO in many languages, even proudly functional ones like Clojure, so that doesn't seem to be as make-or-break as you and I would have expected. (Clojure does have recur though, but it doesn't help for mutual recursion.)
Clojure has no TCO so it can interop with Java. It is the last language I would bring up as evidence.

https://clojure.org/about/functional_programming

I don't think it matters why; the fact is that it's a popular "functional" language that doesn't support (full) TCO.
>There's no TCO so writing recursive algorithms from old FP papers is hard.

Why write "recursive algorithms from old FP papers"? As an exercize, or is there a business need?

Inherently recursive algorithms are clearer when written in recursive style.
>There's a complete and total disregard to any notion of a smaller Julia or a Julia more suited for general purpose

That's false. General purpose Julia is a stated goal of the core team, it's just that numerical domination is higher priority.

Also, small binary static compilation with tree shaking is further along than you think

yeah, if anything that's what I dislike about julia, I wish it didn't claim to be a GP programming language, and instead worked more on figuring out how to glue it to languages that aren't C.

For context, I have basically stopped using julia (not for any taste-related reason except I started doing jobs that were more suited for elixir and haven't had to do numerical computation since), and elixir doesn't claim to be a GP-PL and it's perfectly fine and doing quite well.

Is there anything you think that prevents Julia from being general purpose? The main one I run into is that the garbage collector needs work, but fundamentally I don't think there's much that keeps Julia from being good as a general purpose language.
"JIT" (ELAOT) compilation and tail latencies.

Python is a GP pl (not a very good one, IMO, but it is one). For a long time for some distros Linux CLI and even GUI tools were in python. Can you imagine such an ecosystem in Julia? I can't, nor would I want Julia to make the sacrifices it would need to make to fulfill such a role. There are so many things that python is "mediocre, but good enough" at, that Julia is quite frankly terrible at, because of the (good for what it does) choices that Julia made.

I wouldn't write a quick CLI using Julia (versus a long-running or test runner CLI - I have done this professionally [0]). I wouldn't write a web server that is expected to take a load (a personal website is probably fine, though probably still quite painful). I wouldn't write Anything embedded.

[0] Wrote a containerized storage block device performance measurement tool. Julia was useful to generate and track statistical distributions of random reads and writes with very clear and concise code.

I also think Julia's concurrency story is not that great. But I'm biased against every PL since I have spent a ton of time in erlang/elixir-land which currently has the only (high level) concurrency story that makes any sense IMO.

I liked when Julia's concurrency was done per-process (still lives on in Distributed.jl, iirc). I get that this has performance implications, especially around spawning and expensive communications, even with MPI, but I kind of wanted some sort of non-locality of data to be acknowledged, and maybe I would have preferred the new threading concurrency to work with the Distributed.jl abstraction. I think it would have been even more awesome if Julia GPU treated computation against gpu arrays in the same fashion as a distributed job... But as of the last time I used julia (it's been a while) that wasn't the case.

I do wonder if you'd see similar reactionary claims about Elixir being a general-purpose language if the community experienced constant shallow and misinformed claims to the contrary (which Julia has in abundance, for some reason). Imagine if every 10th post about Elixir on HN was "I will never use it because I work in embedded and it has zero support there" when Nerves is a google search away.

From another perspective, if we consider "general purpose" to mean "focuses on most of the things I care about", then you could argue (and I'd agree) that Elixir appears more general purpose for a larger number of people. Specifically, most devs work on networked services, and networked services are bread and butter for BEAM languages.

Lastly, there is also a strong tendency to dismiss anything with a whiff of academic attachment as unfit for "real" industry work. This effects not just Julia, but also Scala, OCaml, Haskell, TLA+, and more. Though I do empathize with the perspective, It is often taken to the point of caricature-you can show someone a dozen companies using some tech and it'll be as if you said nothing at all!

(comment deleted)
Often the lazy pattern for evaluating iterators has bad "mechanical sympathy" and the strategy of "evaluate step 1, write it into a list" and so forth often beats the "step 1 calls step 2 calls step 3..." pattern by an order of magnitude in performance.

You just win so much by keeping the inner loop in the I-cache, having the branch predictor completely focused on one inner loop at a time, etc. Writing/reading the array burns memory bandwidth but the CPU usually likes the access pattern.

True the eager approach can fail terribly if the array is huge and it's particularly obnoxious if you are running 10^6 calculations and just one of them makes a big array, but the lazy approach is one of those lower teachings that gets passed off as a higher teaching.

I think what you really want is a jit compiler that decides what to evaluate on a case by case basis. Julia has nearly all the inputs it needs to do this well… it just doesn’t
It's probably just a huge bias, but I feel that, as a programmer matures and experiences more and broadens his or her horizons regarding programming languages, he or she takes a road from dynamically typed languages to statically typed languages, often going through lisp as an intermediate step.
That's what a programmer mid-way to maturity would do.

When the programmer finally reaches enlightenment they see that static types have their own burden, and Lisp or Smalltalk or Forth or Erlang, can be the final step, not some gateway drug to static types. Heck, C and C++ ain't bad themselves.

So the answer to the question of life is c++?
Yes, that's the moment you finally accept that reality is just plain shit sometimes, but you need to deal with it and move on.
> and Lisp or Smalltalk or Forth or Erlang, can be the final step

Nah. Final boss programmers (Fabrice Bellard, Mike Pall, etc.) work in C. (Or maybe sometimes a bit of C++.)

For systems works maybe.

Most impressive application programs and games I've seen were in C++.

But I've seen boss programmers do wonders in all kinds of languages. Didn't this Notch guy make 2.5 billion in a game he wrote in Java?

Notch is in no way a "final boss programmer". (In fact, him being a successful businessman clearly points to the fact that he isn't.)
I don't even look at dynamically typed languages anymore. And once you learn about dependent types...
I don't think this is universally true, no. Historically there have been large migrations of developers from traditional statically typed languages towards Ruby/Python/JS/Groovy/Clojure. In fact, Clojure was designed by and is used by well experienced developers fed up with the added complexity of type systems.
By "traditional statically typed languages" I assume you mean things like C or Java, whereas I'm talking more about Haskell-like type systems. Perhaps that's really an optional first step in the journey: from [Java to] Ruby/Python/JS/Groovy/Lua [to Lisp] to a language with a real type system. The further along you go, the more mathematification your programming undergoes.
I think this is a bias. There has been a move from Java/C++/C# static to Python/Ruby/PHP/JS dynamic but now people are adding types back to Python, Ruby, PHP and JS. There is also a move from Java static to SML-like static (so Rust for example). Static and dynamic are not the only way to categorize languages and hide some importants things.
But doesn't the fact that people are adding types to dynamic languages, and the fact that TypeScript is a very popular way to write Javascript, and, as you say, that people are moving from terrible static type systems (Java) to better ones (Rust) prove my point?
I think some people could (and will) argue that you haven't tested real dynamism until you've used Smalltalk or Common Lisp and that there could be a shift from Typescript/Rust to these. That's not my opinion, but it seems fair. There are often cycles like that, with each side getting better at each cycle.
Great article, thanks for writing this, I’ve had a lot of frustration with the Julia community being unwilling to see faults in the language.

I really want to like Julia and I think I’m theory it has a lot to offer but due to much of what you listed I find it hard to develop in.

One thing I would add is that package management is also odd to me. It seems to have a lot of overhead and behave in unexpected ways.

In general I think Julia could learn a lot from Go. When I develop in Go most everything is simple. The type system is easy and just works, packaging is simple and usable, it compiles quickly. I fend writing the language seamless and productive.

Unfortunately Go also isn’t good for data science due to the memory model so Julia has a lot of room to step in there.

> I’ve had a lot of frustration with the Julia community being unwilling to see faults in the language.

How about just moving on? It's not like there is a lack of languages and tools out there.

All languages have problems. Don't take my post to mean "don't use Julia" - the very first words of the post is that it's my favorite language. Also do note that the webpage is built with Julia. Not a coincidence.

But even good systems need critique, otherwise there can be no improvement or growth.

Your praise for Rust combined with the list of Julia problems left me curious what you find redeems Julia even though it has all these problems.
Rust is too low level for most data scientists, the borrow checker interrupts the flow of thought and it doesn’t work well in notebooks.
Yeah, I guess only seeing one side of the argument can be a bit misleading...

It would probably take another 1,000 word blogpost to go through why Julia is amazing, despite all these problems. I'm sure I will make that post someday.

While I do like Rust, the basic design of Julia and Rust are just very different. They're intended to solve different problems, and the problems I have are the problems Julia is designed to solve. The love comes from just how well it solves those problems compared to every other programming language out there.

Compared to Rust specifically, Rust is a complete nonstarter for interactive coding, since there isn't a REPL. Even if there was, it's way too complicated to use interactively - a garbage collector would be a must, and a lot of these compile time checks that I praise would be a major pain in the ass when coding casually. It's also way too slow to write: Even after having written Rust for a few months, I estimate I can solve a problem using Julia 4 times faster than using Rust, using maybe 2/3 the number of lines, or less.

> How about just moving on?

Things can have faults and be worth investing in, it doesn't need to be an all or nothing false dilemma. Nothing would get fixed if we all just self selected in this way.

To do data science there kinda is; it’s python, Julia, R, c++ or a bunch of not well supported languages

Nowadays I’m doing my ML in rust which has been pretty nice, but the borrow checker does bite you a bit and there’s not much of a community.

Julia seems really promising, the community just gets their head in the sand a bit

I think you just made OP's point.
That was explicitly not the OPs point. His point was that there are warts on every tool and he wanted to clearly bring them up in a way that is productive and helpful.

He says julia is his favourite language in the very first sentence.

jefft meant GP, not OP. When people complain about julia, they often get "maybe julia isn't for your use case" instead of "good point, we should fix that".
(comment deleted)
Exactly; sorry for the confusion
As someone who has used Julia for production use, I basically agree with everything you've said.

IMO:

1) Julia rushed to v1.0, but its understandable - it is sort of a catch-22 issue. More developers won't join unless it is stable (v1.0). But it won't get stable unless a lot of developers use it and feedback is heard.

2) I personally found that Julia community is slightly hostile to feedback and negativity. May be it is just me but it has way too much hype-driven-positivity that leads to delusion.

3) A lot happened between v0.2 to v1.0 which IMO should have been carefully and slowly done.

4) Developer experience should have been one of the major focuses. Stack traces should be beautiful and absolutely transparent. Debuggers are clunky - I used the Atom (Juno) debugger and wanted to toss the laptop off the window - just shows how frustrating it was. Compile times and smoothness of dev experience pays dividends and it was largely ignored.

5) I really like official libraries, not SomeBasicFunctionality.jl dependency. I am spoiled by Python.

6) Marketing around speed is misplaced IMO. It lures people like me into fanboys of Julia. There is so much more to a programming language than speed.

I don't want to be overly negative. The language and the original paper is beautiful - and this is all hard stuff. Kudos for the progress made so far.

Note that stack traces are a bunch better in 1.7 (not yet perfect though).
I like that they are colored now, but really what needs to be added is type parameter collapasing. In most cases, you want to see `::Dual{...}`, i.e. "it's a dual number", not `::Dual{typeof(ODESolution{sfjeoisjfsfsjslikj},sfsef,sefs}` (these can literally get to 3000 characters long). As an example of this, see the stacktraces in something like https://github.com/SciML/DiffEqOperators.jl/issues/419 . The thing is that it gives back more type information than the strictest dispatch: no function is dispatching off of that first 3000 character type parameter, so you know that printing that chunk of information is actually not informative to any method decisions. Automated type abbreviations could take that heuristic and chop out a lot of the cruft.
this would be beneficial not just for stacktraces but for printing values, too.
Well said, point 4 really resonates with me, they seem to want to be different over just using things that work well
Completely agree with 4 and 5. I use Julia regularly and while it is great for scripts and proof of concepts of mathematical stuff it might be too complicated to implement in Python or in C++ once one starts to grow an application it is tremendously frustrating.

I have clear and satisfying workflows in C (vim + make + gdb + valgrind) and Python (vim/vs code, pdb) but I cannot say that debugging and tracing errors is a comfortable experience in Julia. Essential development tools are relegated to third-party libraries (e.g. Revise.jl and Debugger.jl) and are often clunky or responsiveness is limited (e.g. Revise.jl won't work when you change a struct)

I believe the problem is that, because of Julia is marketed towards scientific computing and HPC, it draws mostly from an academic user base which is not that interested in software development.

> I believe the problem is that, because of Julia is marketed towards scientific computing and HPC, it draws mostly from an academic user base which is not that interested in software development.

Although you have a point regarding Revise and Debugger, the last paragraph makes no sense at all. As a counterexample, Haskell drew mostly from an academic user base and many Haskell idioms have ended up in other real world *production* languages like Python (e.g. map, filter, reduce).

> It does not make sense at all.

Please, I am open to see why you think so.

> As a counterexample, Haskell drew mostly from an academic user base

May I infer from this statement that you agree with me that Julia draws mostly from an academic user base? In that case, I do not see how your counterexample invalidates what I said. Perhaps some constructs from Julia end up in "real world production languages" but what I said is that the development experience in Julia is subpar and it shows when one is trying to develop larger codebases where software engineering practices become more important.

> I personally found that Julia community is slightly hostile to feedback and negativity. May be it is just me but it has way too much hype-driven-positivity that leads to delusion.

Part of the problem, at least from what I observed here and in other dev communities, was that Julia had a large number of bad faith critics (probably larger than the number of active users, at the time) from about 0.2 to 0.5 or so. I'm talking about everyone who compared the runtime of hello world in the REPL, with start up time, to that of a compiled executable. There were piles and piles of fake benchmarks that did little more than compare BLAS bindings as though the differences were intrinsic to the language.

Sure, the Julia community could have reacted better to such (and a few people did: BenchmarkTools.jl was an early win in this area), but few people do react that way in practice.

Yeah, that might be true. I've read very poor criticisms of Julia other places on the Internet. Most famously perhaps the "giving up on Julia" blog. In fact, the lack of good criticism was what prompted me to write this post.
I probably should have added that I certainly find your post to be good criticism.
Point 4 is going to get explicit dev time after the initial stages of the new general purpose compiler plugin infra is completed.

Then, proper debugging and introspection tools will be easier to build.

Others have commented on stacktraces, so I wanted to mention that the debugging experience in VS Code (the replacement for Atom-based Juno) is much improved as of the past couple of months. Worth a revisit if you're using it already.

Regarding stdlib support, I feel like it's a toss-up. For numeric and data processing code, Julia has a much richer stdlib whereas I need at least Numpy in Python (and even then, working with anything not array-shaped is a pain). For more systems-y stuff though, Python has a much fuller stdlib (e.g. reading/writing a bunch of archive formats). The end result for me is that scripting with Julia feels high friction, and doing anything which requires any kind of throughput with Python feels like pulling teeth.

Agree with all of this except

> 5) I really like official libraries, not SomeBasicFunctionality.jl dependency. I am spoiled by Python.

Python's standard library is full of bad code that nobody has time to improve [1]. Over time, Julia packages will surpass the standard library too but we'll still be hauling it around and spending core-dev time on it for for backward-compatibility reasons. We should have a much much smaller standard library.

[1] https://pyfound.blogspot.com/2019/05/amber-brown-batteries-i...

I think the only difference is whether something is officially supported or not. When it is officially supported, it tends to not break and has to run through a bunch of tests that ensure that std lib doesn't break with every programming language release. It tightly couples them. With off the shelf libraries, there is always a delay.

I also have an ideological take - I think of programming languages as a tool box and like a car mechanic, you want to have dependable tools that are robust, don't break and has good support. Basic algorithms and datastructures should always be included in the programming language - this is subjective but I firmly believe in it.

(comment deleted)
> 2) I personally found that Julia community is slightly hostile to feedback and negativity. May be it is just me but it has way too much hype-driven-positivity that leads to delusion.

I want to push back on this a bit, which I acknowledge is very ironic. In the past few years people consistently post on Discourse asking for fundamental changes to the language to make it more resemble python, C++, or whatever their preferred language is.

People often say Go is great because there is "only one way of doing things", yet people are very resistant to being told "the way" to do something in Julia. This has happened enough that it's prompted a pinned PSA on discourse: https://discourse.julialang.org/t/psa-julia-is-not-at-that-s...

It gets tiring! And i'm not sure how the community should handle these requests, but I don't think it's fair to blame all of the negativity on the Julia community when these somewhat misinformed, or even bad-faith posts are so frequent.

>I’ve had a lot of frustration with the Julia community being unwilling to see faults in the language.

What? It's basically a meme at this point for major contributors to write a list of what they think is bad. The language's creator did a nice Youtube video "What's bad about Julia?" at JuliaCon 2019 (https://www.youtube.com/watch?v=TPuJsgyu87U), one of my most popular blog posts of all time is "7 Julia Gotchas and How To Handle Them" (https://www.stochasticlifestyle.com/7-julia-gotchas-handle/), etc. What the community pushes back about is things that are factually incorrect or just silly and repetitive, like the n+1th discussion about 1-based indexing. It's stuff below like, "I want to do an interactive workflow but not use the REPL, so it's not working well"... well the REPL is literally the interactive piece that caches the compilation so just use it if that's what you're trying to do? Yes, nobody has time for that nonsense, but everyone chimes in for real substantive discussions like changing the Base iterator API, programming patterns that would reduce recompilation, etc.

I don't think that's fair. Your blog post is not about what you think is bad - at least, it doesn't read like it. It reads like a list of stumbling blocks and how to get around them. This is not the same as listing the major problems with the language.

Jeff's talk is indeed great, but... it's not mostly about what he thinks is bad, either. That part is quickly swept aside with "just so you know we know". The talk is really about some very specific problems in the type system that are so obscure that I don't even consider them worth mentioning in a blogpost about Julia's weaknesses.

>It reads like a list of stumbling blocks and how to get around them. This is not the same as listing the major problems with the language.

I mean, if by stumbling blocks you mean all of the things I thought was bad and all of the work arounds you have to know to get work done? I think the difference is that normally when I gripe I like to then elucidate why the bad things exist. To me that's more productive because digging into "why is it like that" starts to point towards "how do you fix it". But yes, giving the full detailed backstory behind what leads to the gripe naturally softens the blow because the reader then understands its purpose, but that's just reality. Very few things are truly and purely awful when you really see the full reason for them. Usually it's just an engineering trade-off.

This feels like classic feedback from the Julia community. It really stifles any hope I have of the language recovering. I know there are reasons behind things, but they also seem blind to fixing the obvious stuff because of them
And yet, would you not agree that the most important pain points do improve over time? Most of the things I mention in the post: Latency, stability, ecosystem maturity, static analysis and the IDE experience is notably better now than just 1 year ago.
Yes "user experience" things like that are improving. And StaticCompiler/GPUCompiler is making good progress.

But I see no movement on the deeper problems, like the limitations of the type system (no effort on traits, function types, interfaces, etc).

I agree progress on the deeper problems is slow, and I also think that it is slow because 90%+ of the issues people have with Julia are "user experience" things (see any of the help forums as well as all of the previous HN discussions). Given a limited amount of resources, it's difficult to justify a deep dive into revamping the type system (AIUI multiple dispatch with complex types + traits is mostly unexplored territory) over improving latency and tooling. That's not to say it shouldn't be done, but in the absence of some significant (financial and development) support behind it I don't think the type system work will be prioritized.
(No response needed, just something to consider.)

In any large system, there are many problems that could have technical solutions but they're missed for one reason or another. Design mistakes occur from time to time and we can choose how we respond when they do. I want experts from other communities to join us, and they need to see that Julia will take their feedback seriously. With all due respect to your major contributions, I think we'll be better off if people in leadership roles take a more critical view of Julia, especially in public.

Any language has stumbling blocks. That's _really_ different from fundamental issues with the language. There is no working around most of the issues mentioned here.

I think a million and one posts on 1-based indexing and "why no OOP" or some perceived weakness of the modules system and other silly things like that have led to a base defensive attitude.

But this post is criticism from someone actively using the language, well thought out, and things that you can not work around. It includes real currently unresolvable pain points.

And it doesn't sound like the Julia lang team has a plan for how to address them. Or it's not communicating that plan. After all, the talk you link by Jeff Bezanson name checks many of the issues raised here two years ago, to then continue to not talk about them ever again.

(comment deleted)
>> I’ve had a lot of frustration with the Julia community being unwilling to see faults in the language.

> well the REPL is literally the interactive piece that caches the compilation so just use it if that's what you're trying to do?

This answer may be exactly the kind of hostility that the GP is talking about.

People may have legitimate reasons for not using the REPL. Instead of adressing these reasons you dismiss them. A textbook case of "holding it wrong".

The thing is no one is saying that starting a process every time isn't a valid way to work — it works great in most scripting languages. What people are saying is that since it's slow and annoying in Julia currently, you might want to consider a REPL-based workflow with Revise. If the response to that is "But I don't wanna use the REPL!!" then what can one do? Ok, don't use the REPL. But as everyone has agreed, it's going to be a bit annoying. If that's a dealbreaker for you then you may not want to use Julia just yet — which is totally ok!

That interaction unfortunately seems to often get characterized as "The Julia devs don't care about startup time! They insist on REPL-driven development and refuse to work on it." Never mind that improving startup time and package loading has been the number one priority of the compiler team since Julia 1.0 and that it's gotten about 10x faster. There's also ongoing work to make it even faster using system images.

Sounds like expanding this into a blog post would be helpful
> I’ve had a lot of frustration with the Julia community being unwilling to see faults in the language.

A related thing that really turned me off in the early days was one of the main developers constantly criticizing other languages. That wouldn't be so bad by itself, but much of it was uninformed, and it told me at least one of the core devs was not going to learn from other languages. There was always an attitude that "I know what to do, unlike everyone else".

The reason I never moved heavily into Julia was that it was too easy to write slow code (back then, things may have changed) relative to compiled languages like Fortran. Maybe I'd have stuck with it longer if I found the community to be pleasant, but an unstable and often slow language plus an unpleasant core developer was more than I was willing to put up with.

Opposite experience here, it was crazy to me how fast I could prototype my number crunching on price series, how trivial it was to distribute it across multiple machines in my house and finally how easy it was to flip to gpu computation. On every step I was surprised how fast it was.

Community is great, met only kind people, exceptionally knowledgable bunch.

A couple of very vocal individuals have an attitude, which reflects badly. But the community is getting bigger, so it's becoming less of an issue as most interactions don't include those people.

It's still easy to write slow code. But writing fast code is often easier than it would be in C++ or whatever.

Come try again if you like.

The announcement post for Julia was literally about all the things we love in other languages:

https://julialang.org/blog/2012/02/why-we-created-julia/

There is a certain set of languages that the Julia team is experts in. But the world of languages is very diverse and big parts of it are lacking representation, so we miss out on their insights. Eg I think most core devs are experts in C, C++, Matlab, Python, but not as many experts in Haskell, OCaml, Rust, Racket, Common Lisp, Clojure.

I'd like to find ways of attracting those other experts into our community, and making sure we use their insights whenever we can.

Always good to attract experts from other languages. I was mainly addressing the claim that Julia core devs like to crap on other languages, not trying to claim that we're experts in every language — obviously we're not. But saying that we're uninterested in other languages or unwilling to learn from them is simply untrue — we're a bunch of huge programming language nerds and we love programming languages, even some of the notoriously flawed ones like C++, Matlab and Perl.
It’s easy to write slow code in any language. I wrote some slow Fortran before I learned how not to. Generally you need to know a good amount about not only the language, but about the machine you’re targeting, to write really efficient code.
I don't think Julia is trying to be anything like Go and it shouldn't be.

Probably Julia's best feature is the powerful metaprogramming support that allows you to, e.g., create array packages that automatically run code on GPU. You can't have such features with a simple language.

That doesn’t mean it can’t learn from it. Yeah they are solving somewhat different problems but in sheer usability of a language Julia could take a lot from Go.
> powerful metaprogramming support ... can't have such features with a simple language

Various Scheme implementations are among the simplest languages I've ever used yet possesses some of the most powerful metaprogramming I know of. Perhaps I misunderstood you somehow?

Have you used Go? It exhibits a very different kind of simplicity than e.g. Scheme implementations.
Adding to the list - the way it treats namespaces.

"using Library1, Library2" at the top of a file makes it difficult to figure out where each function comes from. It's like "import *" in Python.

Yes, I should have added that. It intersect with the type system in a complicated matter, since two functions can co-exist in the same namespace as long as their signatures are incompatible.

Which of course means that, if I'm correct that the community is moving away from type signature as much as possible (they will still be needed to some extent to control dispatch), the problem of namespace collisions will increase over time.

I think you're completely right with this observation. In practice much of Julia is duck typed. It uses types to pass information from the outermost caller to the compiler of the inner functions, not to express invariants.

Human annotations get in the way of that, and thus get in the way of composability.

You want to annotate Interfaces in Julia, not types. But we don't have interfaces.

Aren't namespace collisions the feature that makes multiple dispatch so composable? I think this is what allows to replace the built in Arrays by GPUArrays and most of the code should still work because all the major operators and functions have GPU implementations
They aren't collisions so much as overloads. e.g. GPUArrays implements the same base AbstractArray methods. I'm not a big fan of using either (in any language) because it obscures where imports come from, and AFAICT overloads are created even with a plain import.
> since two functions can co-exist in the same namespace as long as their signatures are incompatible.

This doesn't really make any sense. You can only have one function in each namespace, this function can have multiple methods extending that function. As long as you are not doing type piracy you will not implement the same method in e.g. different packages.

The problem with `using` is mostly about that it is unclear from what namespace a symbol comes from since it isn't visible lexically.

this works fine for me

    import Dates
    Dates.today()
It is a lot safer than `from pkgfoo import *` because you get a warning if there is a collision.

    $ julia --banner=no
    julia> module A
        export foo
        foo(x) = x
        end
    Main.A

    julia> module B
        export foo
        foo(x) = x + 1
        end
    Main.B

    julia> using .A

    julia> foo(1)
    1

    julia> using .B
    WARNING: using B.foo in module Main conflicts with an existing identifier.

    julia> foo(1)
    1

    julia> B.foo(1)
    2
Re point 1 (JIT latency): This has been done to death, but truly fixing it would make Julia part of my toolkit. For example, right now I'm experimenting with numerical diffeq solvers for chemistry. It involves experimenting with parameters, and plotting. AFAIK, this isn't possible with Julia unless I switch to a REPL or notebook workflow.

This brings up a key question: What is the technical limitation behind compiling dependencies every time you run the program? Is non-REPL workflow an afterthought? I'd rather use Rust for something like this! `cargo run` works faster than Julia's JIT since it doesn't need to recompile dependencies like a plotting or numerical lib each time I change a parameter.

Out there idea: What about a new language that takes advantage of Julia's strengths, like clean mathematical syntax, 1st-class array support, and being a fast scripting/numerical language, without some of its problematic design decisions? Julia's been the language I've been wanting to love for years.

It's a fundamental problem of having a dynamic, compiled language. It's not possible to actually solve. Think of it similar to how C++ and Rust needs to compile its source code before running it. No-one talks about this as a problem to solve.

The problem with simply compiling dependencies to static binaries is that all Julia code is allowed to redefine other Julia code. So package X can load package Y, then define a method that causes package Y to change behaviour, and thus needs to be recompiled.

This is not unintentional, by the way. Having packages able to use each other's code is critical for having the ecosystem be "composable", that is, being able to make two different packages work effectively together. For example, I might take a type from package X and throw it into a function from package Y, and it works.

C++ and Rust don't need to compile dependencies between program code modifications. Compiling a Rust program is faster, anecdotally, than running an equivalent Julia one. At least for the numerical and plotting uses I've tried.
> It's a fundamental problem of having a dynamic, compiled language. It's not possible to actually solve.

There are plenty of Common Lisp implementations that allow you to redefine functions or add methods to multi-dispatch functions without requiring you to recompile every use-site. There are other trade-offs here, but it’s not “impossible” to precompile and optimize code in a dynamically-typed language.

I disagree that it cannot be obviated in Julia. Can be solved with one or more of static tooling (ie proving there's no overwriting), tiered compilation with a faster interpreter and sealed modules. All things jeff et al have been discussing
I don't think this is an inherent problem of having a compiled dynamic (in other words, JITted) language.

Things like Javascript (V8) and Lua (LuaJIT) manages to have fast startup times while having exceptional performance in hot paths - this is because they have a fast bytecode interpreter that executes the script first while the actual compilation is taking place. Unfortunately Julia in its current state, doesn't have a fallback interpreter to execute its bytecode/IR (which is similar to LLVM IR). And LLVM IR isn't really suited for fast execution in interpreters - it's moreso designed as an intermediate language for a heavyweight compiler than a bytecode for a dynamic language.

Maybe some heroic figure would come out of the fog and suddenly brings a whole new bytecode representation and a fast interpreter for Julia, but that would be quite a project..

Julia does have a minimal compilation path with an interpreter. You can even configure this on a per-module basis, which I believe some of the plotting packages do to reduce latency. There is even a JIT-style dynamic compiler which works similarly to the VMs you listed: https://github.com/tisztamo/Catwalk.jl/.

IMO, the bigger issue is one of predictability and control. Some users may not care about latency at all, whereas others have it as a primary concern. JS and related runtimes don't give you much control over when optimization and are thus black boxes, whereas Julia has known semantics around it. I think fine-grained tools to externally control optimization behaviour for certain modules (in addition to the current global CLI options and per-package opt-ins) would go a long way towards addressing this.

You're right, done some more research and there seems to be an interpreter in the compiler: https://github.com/JuliaDebug/JuliaInterpreter.jl. It's only enabled by explicitly adding annotations in your code, and is mainly used for the internal debugger, but it's still there.

Still, it still seems to try executing the internal SSA IR in its raw form (which is more geared towards compiling rather than dynamic execution in a VM). I was talking more towards a conventional bytecode interpreter (which you can optimize the hell out of it like LuaJIT did). A bytecode format that is carefully designed for fast execution (in either a stack-based or register-based VM) would be much better for interpreters, but I'm not sure if Julia's language semantics / object model can allow it. Maybe some intelligent people out there can make the whole thing work, is what I was trying to say.

The naming is unfortunate, but JuliaInterpreter is not the built-in one but a separate package for use in external tooling. The built-in one can be run globally via the --compile=min CLI flag. Likewise, you can also pass -O0 to -O3 to configure the level of optimization (which, predictably, affects latency).

As for IR representation, I'm not aware of any limitations of the IR (remember, there are multiple levels) over a LuaJIT-style bytecode for interpretation performance. After all, the Futamura projections tell us that a compiler is really an interpreter that's undergone some partial application. Of course, that's a theoretical correspondence that has little bearing on real-world performance, but I don't think you can confidently say that Julia's lowered or unlowered IR forms are fundamentally bad for fast interpretation.

You can set optimization per module with `Base.Experimental.@optlevel`, though I'm not finding any documentation for it. Could swear it was in a release note.
Yep!

  help?> Base.Experimental.@optlevel
    Experimental.@optlevel n::Int

    Set the optimization level (equivalent to the -O command line argument) for code in
    the current module. Submodules inherit the setting of their parent module.

    Supported values are 0, 1, 2, and 3.

    The effective optimization level is the minimum of that specified on the command line
    and in per-module settings.
Inside Julia compiler/runtime there is an interpreter, because Julia uses a heuristic to determine whether to compile or interpret a function. There is also interpreter code in Julia debugger. I don't know how full featured they are, but one does not have to start from scratch.

On the other hand, implementing a tracing JIT for Julia is going to be such a big task, I am not sure how much help existing interpreters are going to be. At the very least there needs to be a new GC, which necessitates changes everywhere except the parser. LLVM integration may also prove awkward for a tracing JIT.

You compare it to Rust compile times, but Julia's are much worse than Rust's. I say this as someone who has used both languages quite a lot.
It’s not really a problem with dynamism, it’s more about the fact that Julia’s compilation model is similar to C++ with templates but at runtime (and with first class parametric types instead of textual substitution, but the compilation and specialization story is similar). Just as separate compilation isn’t possible for C++ template code, it’s a challenge for Julia as well.
> No-one talks about this as a problem to solve.

Maybe you just don't read the right places because people definitely talks about this as a problem to solve. For example, Julia already stores e.g. inferred code in the precompile files. There isn't a huge leap to also stored actual compiled code from that. Just because it is possible to invalidate code and cause recompilation doesn't mean that it isn't worth storing ahead of time compiled code in the 99.9% cases where invalidation doesn't happen.

But this is not solving the problem, it's just reducing it. My analogy with compilation of C++ is that noone SHOULD expect it to be "solved", because it's a natural consequence of how the compilation works. They may improve e.g. incremental compilation to reduce compile times, but it's just not a problem that can be "solved". Similarly with Julia and latency.
I don't see a difference between solving a problem and reducing it to not be an issue (or problem) anymore.
The hard part is making it produce the correct results even if the user does something like change the definition of +. It's not un-solvable, but it needs a couple hundred hours of work by people who are very busy.
I think the REPL workflow is a huge advantage for experimentation and explorative programming. I assume you are supposed to and are able to have a file buffer open and attach your REPL to that, avoiding restarts. Is that assumption correct? In this case I cannot imagine how a compile-run workflow has any advantage for the type of work you are describing.
The problem with the REPL workflow is that it forces the user to track a lot of state. You can find yourself constantly trying to remember if you remembered to re-evaluate an important line. I've found that -- for anything but the simplest problems -- it's better to write nicely parametrized scripts and run from the command line.
Pluto (reactive execution) and Revise (automatic re-evaluation) are the standard solution for this problem in the Julia ecosystem. Not that your workflow should not be supported too (people are working on it), but alternative solutions preferred by much of the current Julia community do exist.
No - I'm not familiar with a file buffer. That sounds like a neat concept I'll look into for Python too. In general, I've been moving away from REPL workflows due to hidden state and lack of reproducibility.
fwiw Pluto.jl notebooks are quite usable and output normal .jl files that can be consumed in, e.g. CI or as a library.
For this type of work you can use PackageCompiler to make a binary that will start up quickly; all the dependencies will be frozen and compiled in.
I agree with much of what the article gripes about. To me it's not prohibitive, and obviously brilliant stuff is being built in Julia as it is right now. But I just feel that things could be that much better.

That said, I do feel some of the defensiveness around these topics from years past is fading somewhat. Still, while some of the things are fixable in Julia 1.X, others likely will require a 2.0 release...

I have to admit never really dug into Julia. When it was new I read about it as I was looking for a replacement of python/numpy. But then I was really repulsed by the fact that array indices don't start at 0.

c.f. https://www.cs.utexas.edu/users/EWD/ewd08xx/EWD831.PDF

As someone who felt the same way, trust me. You'll hit it twice, and then start using eachindex/ begin,end and then you'll not notice it anymore.
In practice, indexing is the least of anyone's problems. I switch between 0- and 1-indexed languages a lot and it's never an issue, I don't even have to think about it.
I disagree. When immersed in a language it doesn't tend to be an issue, but switching between them absolutely is. Over my career I've had to deal with a ton of off-by-one bugs in code that was prototyped in Matlab then ported to C++. My hope with Julia was that the language was fast enough that you wouldn't have this divide between prototype and production, but given the overhead in using it anywhere but a REPL, it doesn't look like things are going to work out that way.

On it's own, 1-based indexing certainly isn't enough to keep me from using a language though.

This was my experience as well.
Starting arrays at 1 deeply and personally offends me as well, but I honestly can't see that as being a reason to discard a programming language TBH.
As someone who's coded with both schemes, I really don't see it as being an issue - it's the equivalent of "I won't use Python because of whitespace."
I plan to train an NLP bot from Hacker News 1-based indexing discussions to automatically generate the mandatory thread on it so that nobody ever has to participate in it again. It's so unoriginal that it's a better fit for ML automation than a human brain.
Also these comments just tell us about the background of the commenter, and nothing else. Anyone who has had to translate numerical or scientific algorithms into both C and pre-array syntax Fortran finds Fortran’s 1-based indexing to be a more natural fit, I would suspect.
> Also these comments just tell us about the background of the commenter, and nothing else

I was about to say something similar, but the last time I did, people got upset ;-)

That and people complaining about certain characters being allowed in variable names in some languages (e.g. hyphen, question mark, etc).

Honestly, significant whitespace is a far more annoying design choice than 0 vs 1 indexing.
A side note: wow Dijkstra really has some top-notch handwriting.
This really isn't a big deal. I switch between C/C++/R all the time and mixing zero/one indexing isn't some huge mental burden or source of intractable bugs--you get used to it after a few days.
> Large memory consumption [...] 150 MB for hello world.

My personal tests showed similar results. Good to know that I wasn't doing something wrong.

The compile time latency is the biggest the biggest show stopper for me.

Yes, you can cope with it by staying in the REPL and they are actively working on it but it is very unfortunate that the "slower" competitors like Python and R feel so much more responsive while developing.

Other than that, Julia is a absolutely beautiful language. Sure, it is not offering the same static safety as Rust or Haskell but I would not hold that against it. There is always some trade offs to be made regarding the dynamic vs static spectrum and the dynamic aspects serve Julia well for the typical use cases.

The compile time latency is really bad for some libraries. I was recently testing out computing class groups using https://github.com/oscar-system/Oscar.jl and was surprised to hit *several minute* latency due to LLVM compilation. For me, the most striking things are that (1) there is no indication in the REPL that calling a function is slow due to LLVM compilation, rather than the function actually running, and (2) it is difficult to avoid paying the compilation penalty every single time you restart Julia, since caching the JIT in general is a technically very, very difficult problem. I wonder if there is an easy fix for (1) that I don't know about: some way of showing a spinner or something saying "I'm compiling code right now".
Is there also something about timing?

Given that R and Python are so mature and active, this really leaves not much space for Julia. Yes, Julia is faster than R and Python (just the language, not packages), but R and Python can easily integrate with C/C++ and many R and Python packages are in fact internally C/C++. This really leaves not much advantage for Julia against R and Python.

If Julia had appeared earlier, it may have had better position in the data analytics programing ecosystem, and gain more attention and opportunity to grow. Now, the whole data industry is booming, but people would rather contribute to the matured R and Python for real work, instead of waiting for Julia to grow.

I think Julia has a pretty good path forward since it is often faster than C++ (especially once you consider language interop overhead), and it is much more pleasant to write than c++. Since Julia and most of the packages are written in Julia (for the most part), Julia makes it really easy for users to become developers. Python and R have much bigger barriers to entry since users will usually hit a binary blob, which makes it much harder to interact with library implimentations.
I don't think that's so convincing, actually. When I learned programming, Python was _just_ replacing Perl as the "common language" in bioinformatics. Until then, there were lots of people who claimed Perl would essentially never be dethroned because it had become the standard.

The issue is that while _some_ users only experience the surface level of packages like PyTorch, Numpy, SciPy, Pandas, and so on, people who actually have to develop these packages must work with the C++ and C underneath. To the developers, the problem of Python's performance is front and center, and a real issue they face every day.

So, the developer folks will make the switch first, as they realize it's much nicer to develop Julia packages in Julia than it is to develop Python packages in C. Over time, this will mean the development power switches to Julia - and as soon as these developers have build tools as good or better than existing tools, the majority of users will slowly migrate, too.

> So, the developer folks will make the switch first, as they realize it's much nicer to develop Julia packages in Julia than it is to develop Python packages in C.

Not so fast. You should also consider that writing the core in C/C++ allows some of those packages to offer bindings for several languages other than python (for example, both tensorflow and torch have bindings for Go, .NET, Rust, Haskell, R, Java, JavaScript).

This significantly expands the use-cases that these frameworks can cover without requiring a complete rewrite for every platform. For example, it is relatively easy to have data scientists train models with Python and deploy such models to mobile/edge devices and web apps.

That's true, but for most packages, that's not really an issue. I.e. there might be a tensorflow library, but there is no libnumpy or libpandas, as far as I know.

As I also mention in the blog post, if you set out to create fundamental library software like FFTW, you should indeed use a static language, and Julia is no good.

> there is no libnumpy or libpandas

I think this is changing with the rise of Apache Arrow. See eg here, slide 38 and on:

https://www.slideshare.net/wesm/pycon-colombia-2020-python-f...

Arrow is just an intermediary
What is your point? (I honestly do not understand.)

Blackbear's comment was that writing libraries in C allows those libraries to be deployed broadly in many compute environments.

Jakob's reply (as I understood it) was that outside of the big Deep Learning libraries, this has not really happened. There is no C implementation of Pandas that allows for redeployment in other non-python compute contexts.

My point was that, with Arrow, this type of cross platform compatibility is coming to python dataframe libraries. You can prototype Dask code that runs on your laptop, then deploy it to a production Spark cluster, knowing the same Arrow engine is underpinning both. Or at least that's the vision. Obviously Arrow is still relatively young. But the point is, it's far from certain that the long-term global optimum for the ecosystem isn't sticking with "all libraries are written in C".

In response to "rise of," I too was excited about Arrow until I played with it and realized it didn't even provide a shape attribute. Anyways, people shouldn't be dependent on a low level lang like C to write fast code.
Fair. I agree Arrow is still more of a vision than anything else.

> it didn't even provide a shape attribute

I suspect this has to do with the project's focus. I think they aspire to be a back-end to DataFrame libraries, which are generally 2d. I think they (correctly) are ceding the "n-dimensional tensor computation" space to the current incumbents.

Arrow is getting support for N-d arrays, so if anything they're expanding in that area (which is exciting). I don't think they're interested in creating a universal libarrow though, the point of the data format and C data interface is to have languages define their own implementations.
I may be wrong. It happens a lot! But I think Arrow's vision encompasses compute, not just a data format and data interface.

https://www.slideshare.net/wesm/pycon-colombia-2020-python-f...

Slide 43: The "Arrow C++ Platform" encompasses a "Multi-core Work Scheduler" and a "Query Engine"

Slide 38: "It would be more productive (long-term) to have a reusable computational foundation for data frames"

Again, I agree that, today, it's more data format, and the shared compute stuff is more a vision.

EDIT: See also https://ursalabs.org/tech/

For sure, I didn't mean to imply they weren't looking at compute too! https://github.com/apache/arrow-datafusion is another example of the shared compute vision. What I was trying to point out is that (at least for Arrow core) they seem to eschew FFI and generating shared libraries in favour of from scratch implementations in other compiled languages and direct bindings in interpreted ones.
This is doable in Julia too. DifferentialEquations.jl has python and R bindings. I expect more to follow as Julia starts getting more best in class packages.
Writing Python packages in Rust with PyO3 is pretty awesome, though.
What are your favorite open source Python packages written in Rust?
tokenizers is a great example. Some other, perhaps simpler ones, are orjson and tantivy.
I dunno. I have written FFIs in many languages and by far julia was the easiest to call a c abi in.

I would say if anything what holds people back in julia is a drive to RIIJ instead of calling the c abi (despite that julia's linalg basically does exactly that with BLAS).

Lua is pretty smooth in this respect.
> This really leaves not much advantage for Julia against R and Python.

It's a bit of a chicken and egg problem. Really the argument is the problems with dual-language model will never go away, so Python & R face an ongoing cost disadvantage in the long run. However, they are also much more mature.

So assuming previous assertion is correct, you need to get enough people interested in Julia to grow to the tipping point.

I'm not really sure it will work, but can see the argument. After all technically superior platforms for this existed when python got started (heck, early python was next to useless for data work beyond file parsing) but that didn't dissuade it's use. The non-technical arguments made it a good-enough language and once that had momentum it's compelling.

On the third hand, what julia really needs to attract right now is mostly library/package writers - that's a tiny fraction of the users of python, but basically steers "what's next". However, for library writers, how many people might use it can be a deciding factor on investing the time...

> for library writers, how many people might use it can be a deciding factor on investing the time

Yes. Especially given that a high percentage of library development these days is being done by industry, not just academia. (At least in machine learning.) They're not writing packages for fun or for academic citations, they want users.

Julia does appear to have a higher than usual proportion of package authors to total users, FWIW. I think it's both a blessing and a curse, because feedback around gaps in the ecosystem is sometimes brushed away with "write your own package". That is, because a large part of the community writes packages to scratch their own itch (I've yet to see one written for citations), they expect others to do the same (which may not be fair).
It should go without saying that Julia also has had a C FFI for years. And a Python FFI. And an R FFI.

The C++ one was dodgy last I looked (which was several years ago; I'm sure it's better now). In practice I typically wrote explicit C wrappers, restoring genericity on either side of the wrapper. Faintly tedious, but nothing a couple macros couldn't solve.

Yes, Julia has them, but if you use them, it basically renders one of the promised advantages of Julia ("it does away with the two-language problem") moot, as you now have two languages anyway. If you have to languages anyway, why not use one of the more established languages?

----

I personally don't subscribe to the idea that the "two-language problem" is a problem that needs fixing. In the end your stack will have multiple languages anyway, unless you rewrite everything is Julia, which is utopian, so having one more isn't really a problem (and it might also be one that you are already using).

> Yes, Julia is faster than R and Python (just the language, not packages), but R and Python can easily integrate with C/C++ and many R and Python packages are in fact internally C/C++.

This is what I was responding to. The grandparent argued that Julia had less library support than R and Python because, so they implied, those languages could interop with C/C++ in a way Julia can't.

The two language problem refers to code in user space, anyway. It's not like Rust, where there are so many wheel-reinventing projects in progress. If you peruse the main Julia package registry, and you'll see plenty of library-wrapping modules.

Also the slowness of Python is overstated - for many of the niches Julia is targeting, Python is plenty fast if you use NumPy / CuPy / SciPi.

Yes, it's easier to write the equivalent for Julia using native Julia code, but it's not clear to me that the average user will care.

> Python is plenty fast if you use NumPy / CuPy / SciPi.

I think this misses the point. You are basically saying that python is fast enough in cases that someone has written already written a fast package in not-python (plus bindings), whereas the value proposition for julia is basically: writing such packages in the future will be lots better.

Obviously the average user doesn't care, but if enough whiz-bang stuff starts to come out in Julia but not python, they'll move.

I think it will be interesting if enough clever new whiz-bang stuff comes out particularly based on Julia's metaprogramming powers.

However, when talking about the "two language problem", the main issue traditionally was prototyping computational code in Python / Matlab / whatever and then having to drop into Fortran / C / Cuda for optimizing it. That's pretty much a solved problem in Python now - thanks to the well developed ecosystem, you don't really have to leave Python to write fast numerical code.

The first problems I came to Julia to solve were ODE simulations in which it's just as critical that the stuff I write and rewrite over and over again (the actual differential equations of my model and associated simulated controller callbacks) runs fast as it is that the pre-written stuff of the library (the solvers or integrators) runs fast. To the best of my knowledge I can't do that in python.

This example (DifferentialEquations.jl in particular and SciML.ai in general) is one of the places where Julia leads the pack.

When I first used Julia it felt rather strange in a lot of ways (I had used python for about 20 years), but after 2 years when I go back to python (and of course there are places where it makes more sense to use python) it feels primitive as there are a lot of very nice features of Julia that I suddenly miss.

> That's pretty much a solved problem in Python now - thanks to the well developed ecosystem,

I don't understand this argument. The same C and Fortran libraries that make numeric Python fast can be called just as easily from any other programming language, just like in Python.

> you don't really have to leave Python to write fast numerical code.

Well, you need to, for example, if you want to write a new numeric algorithm to call from python. As in, not use a numerical solver, but write a numerical solver from first principles. For that, Python is mostly useless and you'd need to use C or Fortran (or Julia).

Referring to start-up latency, the author asserts:

> But the problem is fundamentally unsolvable, because it's built into Julia on a basic design level.

Citation need. Today, the Julia compiler runs in JIT mode. But there is nothing preventing it from being ahead-of-time compiled (indeed, some work is going behind the scenes to make this happen). There is also an interpreter for Julia. I don't see latency or large memory footprints as being "fundamentally unsolvable".

Yeah, though the solution for it basically seems to be "throw out all the previous code that was highly coupled with LLVM and actually write our own fast JIT compiler and interpreter from the ground up". It's possible, but probably takes an incredible amount of work and would maybe involve cloning a copy of Mike Pall (the creator of LuaJIT) to help on the project.
I don't think you need to rebuild the compiler. Here is a proposal how how this can be done using the work to compile Julia for GPU's:

https://docs.google.com/document/d/1rLpZf-HK6b9uYPDT_piUza4L...

My response's more about the dynamic execution side of things (latency & memory bloat of Julia). Static compilation is a whole different topic, but I'm confident that it can be solved with existing LLVM infrastructure (because what's LLVM good at? static compilation!) The hardest part may be how to modify Julia's semantics to fit that paradigm (for instance, the need to introduce "header files" in the language, and all the gnarly details coming with it)
> I don't see latency or large memory footprints as being "fundamentally unsolvable".

Dunno. Look at Python. Does "never in a million years, because switching to a better language would be easier" count as "fundamentally"?

(comment deleted)
One thing that I miss coming from python to Julia, is typing-as-documentation. In python I often write type annotations that are much more restrictive than they need to be. They work as checkable documentation of how a function is expected to be used (and under what circumstances do I guarantee it will work), without restricting how it can be used.
I think this is a real conflict. In my opinion (not just mine), the only reason to write type constraints on a method definition in Julia is to control dispatch. Adding types to method arguments for the purposes of documentation is counterproductive to generic programming.
You're not wrong. I guess what I'd like is the ability to apply (up to) two type annotations, with the second one a subtype of the first, and use the first for dispatch and the second for documentation/testing/static analysis...

... which actually seems like it might be doable with some macros? Those are beyond my ken right now, but the goal would be

  @doubly_typed f(x::Number|Integer) = x
  f(6.0)            # Same as g(x::Number) = x; g(6.0)
  @strictify f(6.0) # Same as g(x::Integer) = x; g(6.0)
Then you would use @strictify when running tests to ensure that the stricter types in your codebase are all compatible. But you'd still need to figure out what to do about return types and the help command...
I used to think this was true (as a developer of a lot of generic Julia code and small data analysis applications).

But now as a developer of larger amounts of "application style" code, I'm not so sure. In an application, you've got control of the whole stack of libraries and a fairly precise knowledge of which types will flow through the more "business logic" parts of the system. Moreover, you'd really like static type checking to discover bugs early and this is starting to be possible with the likes of the amazing JET.jl. However, in the presence of a lot of duck typing and dynamic dispatch I expect static type inference to fail in important cases.

Static type checking brings so much value for larger scale application work that I'm expecting precise type constraints to become popular for this kind of non-generic code as the tooling matures.

I like Julia because of the trivial 10x performance improvements I get over writing similar code in Python/numpy.

What I don't like is how Julia attempts to force you into a REPL workflow. Everything is optimized for REPL work. I just want to write a script in a text editor and run it from the command line. Please make this easy for me.

(Other HN comments have said this in more detail, for example: https://news.ycombinator.com/item?id=27310747.)

It's really hard to do, because having a command-line centered development experience with Julia is a complete nonstarter until compile time latency is near zero. And that's just really, really hard, and unlikely to happen, at least any time soon.
That is an extremely well put comment in the link. Thanks for sharing it.
> In programming I tend to think the whole computer and its OS and so on as the programming tool. My impression is that for Julia folks Julia is something totally separate from anything else in the computer. But I don't understand why. Is it that its felt that changing syntax on the fly is too cognitively demanding or something? This is something that one gets used to very fast.

This comment really does not resonate with me. It sounds like a criticism of Smalltalk, not Julia. Not sure what it means to change "syntax on the fly", but that does sound like the sort of design that is maximally flexible, at a considerable cost to readability. Macros already allow you to embed DSLs (as long as they parse), and almost everyone agree that they should be used sparingly.

> And also tends to ease the IMHO weird hung-ups on syntax. In fact, I think Julia has made some (IMHO misguided) syntactic decisions because they just want to do something differently from Python just for the sake of being different. I find this totally senseless.

I am not aware of any decision that is done just for the sake of being different. If there are any, then yes that's senseless.

> Not sure what it means to change "syntax on the fly"

GP meant that Julia enthusiasts seem to dislike the cognitive overhead of switching between languages (e.g. Bash scripts, SQL, C code, Python scripts, and as GP wants, Julia scripts as well) while doing multi-language development using the whole Unix computer as a programming tool.

As opposed to doing everything in a Julia REPL.

That comment you linked is amazing - it steps back a little bit and gets our head of out the dirt to see the horizon. As a bunch of programming ostriches try to muck about this or that - the author instructively dictates that general purpose programming languages are part of the toolbox to get the job done...on an operating system of choice.

We need to listen to people that have gone through the experience of putting complex systems together and their learnings are immeasurably valuable. This is the eternal balance of theoriticians and practioners.

It also further cements something that I always felt but can be offputting to some people - Julia is an academic language used by academicians. From a software engineering perspective (not computer science, mind you), there is much to be desired.

I love julia and wouldn't mention this if I hadn't written a big chunk of data-analysis code with it...

It's a small gripe, but one thing that really bothers me is that they gave up on libreadline for the REPL (for what seem like fairly superficial build management issues, looking at the original email threads) in favor of a custom solution, which

* doesn't support vim-like or emacs-like keybindings, and

* won't read my .inputrc file and my customizations

It's just maddening using julia's REPL without this. It's easy to dismiss user complaints like this, but I can go back and forth between bash and into the python REPL and all of my line discipline actually makes sense, but then the julia REPL is broken and clumsy.

Also, pdb.set_trace() is a lot easier and more productive than what Debugging.jl has to offer.

You might have some sort of dangling config issue somewhere? I use the emacs keybindings in the Julia REPL all the time. They work fine out of the box (at least here).
Ah good to hear. I wish I could edit my post. But vim bindings are nowhere to be found.

The good news I guess is that having a clumsy REPL has really gotten me into vim-slime.

Have you tried Infiltrator.jl? It's great for breaking out into an interactive REPL from some inner scope, allowing you to examine the local variables and other program state interactively. This covers the part of the functionality of pdb.set_trace() which I care about.
While all the points are valid what scares me most about Julia is what is covered under the section "The core language is unstable". Recently I tried the latest beta version and came across an issue - I just could not add packages. (`] add JSON` or ). No matter what package I tried to add, it failed with a stacktrace pointing to libuv. I tried downgrading to lower versions of Julia but no luck.

Turns out it is a regression introduced by a commit dated Sep 23 2020. In libuv.

As I tried to fix it, I realized Julia uses a version of libuv that is significantly diverged from libuv main branch ("123 commits ahead, 144 commits behind libuv:v1.x" as I write this comment) and the bug was in the code. Using the code from the corresponding function from libuv upstream fixed the problem.

To summarize

1. There's a bug introduced close to a year ago that breaks basic functionality on a mainstream operating system. 2. Julia has its own version of, of all things, libuv, that is significantly diverged from the original. 3. The bug is in one of the changes introduced.

While each of the above is defensible on its own. Taken together, they do scare me away from considering Julia for production use. I am hoping am wrong somewhere. I think it is a lovely language.

I mean, that's bad and scary, but you did mention that you were using a beta version of julia. Finding this sort of thing is exactly why the beta versions exist.

If the beta was stable and ready for production, it wouldn't be called beta...

I think you missed the point where he said the bug was present in the stable release, too.
Oh I see I did misunderstand. Yes, that is unfortunate. I'd guess that since this made it into a stable release, it's likely a pretty tricky bug to encounter, since the failure is so spectacular.

I will say though that bugs appearing in stable releases of any software is a bad, but practically unavoidable thing. It sucks that this bites people, but it's not what I'd really call instability.

Oh, the problem is present in 1.6.2(current stable release) as well as v1.5.4(released March '21 available under old releases). I could not find any other 1.5+ version to try.
Yes, my apologies, it was pointed out to me below that I misread your post.
Do you have a link to an open issue tracking this problem?

Several Julia core devs are also libuv maintainers or contributors. The main reason for the divergence is that Julia’s libuv fork has a significantly more flexible event loop model that allows using libuv from multiple threads efficiently. The main libuv project has been reluctant to accept that change since it’s a quite advanced capability that Node doesn’t need.

Thanks for response.

> Do you have a link to an open issue tracking this problem?

Yes [#41642](https://github.com/JuliaLang/julia/issues/41642)

> The main reason for the divergence is that Julia’s libuv fork has a significantly more flexible event loop model that allows using libuv from multiple threads efficiently.

Glad to hear this. That's impressive.

Thanks for the bug report (assuming that’s you that filed it). The change that broke this was made first in Julia’s libuv fork but is being upstreamed into libuv main. It simulates UNIX chmod functionality on Windows, which is (apparently) tricky to get right across all versions and all corner cases. Supporting that correctly has been an outstanding TODO in libuv for a long time — what you’re seeing is Julia driving the development of libuv and therefore hitting the bugs first.

This issue was reported seven days ago and is now slated to be fixed in the next release of all affected versions.

I mean, this just looks like your run-of-the-mill bug, or? If you filter on the bug label on GitHub you will find many more. It would be interesting to try figure out what is special about your setup since no one has reported this bug since it got introduced (and it doesn't show up on any of the CI).
I was curious about that too. Many other people use Windows 10 and this is the first time this issue has come up, so there must be something else unusual going on here. If no one could install packages on Windows 10, we'd have heard about it.
I don't buy the argument that not fastidiously following libuv upstream is an example of Julia not being stable. It's the opposite: that's an indicator of some measure of stability.

The situation could easily be opposite: suppose libuv does stupid things and breaks, and so if Julia tracks the daily build of libuv, it breaks.

"unstable" is not a word which means "staying on top of the development of every dependency". That could literally be a clause in a working definition of "unstable"!

If you lag behind in updating dependencies then there will be situations where you don't get some bugfix for a while

Maintaining your own fork is a good idea, because sometimes fixes are security issues from advisories. You don't necessarily want to jump to the latest and greatest libxy.so, picking up 75 other changes to fix one security item: those items are risky, because they can contain undiscovered bugs. You can carry the security patch for now and then drop it when you update.

Indeed. And in this case, the #3 contributor (and #1 in recent times, really) to Julia is also the current primary maintainer of libuv so it’s very unlikely that there would be any critical fixes that would be missed.

This particular example turns out to be a case where a feature was developed in Julia first and there’s some corner case on this poster’s Windows 10 setup that triggers a bug in the new feature.

This article is painfully true. Julia is full of gems, but also features so many warts everywhere that I'm not sure whether it will be able to overcome the latter – I hope it will.

I would add to the author's list the subtle differences between REPL and scripts, the weird obsession of Julia for embedding slightly different and out of date versions of its dependencies (BLAS, uv, LLVM, ...) that makes it a nightmare to package, the painfully slow documentation website, the sometimes surprising function names, and wholeheartedly agree on the failure that is functional programming handling, both in syntax and implementation – which is surprising for a language stemming from MIT.

I love Julia and choose to work in it almost exclusively, but I agree with the points in the article. I've run into a lot of issues just writing numerical linear algebra type algorithms.

Even core, and not quite core but maintained by core dev, libraries like Distributed.jl and IterativeSolvers.jl can feel pretty rough. For example IterativeSolvers has had strange type issues and not allowed multiple right hand sides for linear solves, for years, afaik due to some aspects of the type system and some indecision in the linalg interface. DistributedArrays still is very poorly documented and looks like it hasn't been touched in 3 years.

I've run into problems when I need more explicit memory management, for example none of the BLAS/LAPACK routines have interfaces for the work arrays, so you either get reallocation or have to rewrite the ccall wrapper yourself. It can also be hard to tell where the memory allocation is happening.

My most recent problem had been with Distributed and DistributedArrays, where everything is fine if you just want a basic parallel mapreduce, but has been a huge pain past that. It's not even clear to me if Distributed/DistributedArrays has been more or less abandoned in favor of MPI.jl, which for me removes most of the benefit of writing in julia, since you then have to run it through MPI. There is an MPI sort of interface for DistributedArrays but that part is not well documented and looks like more of an afterthought.

My use case isn't even that complex, I just want to persistantly store some matrices across the nodes, run some linear algebra routines on them every iteration and send an update across the nodes, then collect at the end. If anyone has any idea how to do this correctly in Distributed or DistributedArrays or can point me to some examples that would be amazing because it has been taking me forever to piece it together.

Not going to stop using Julia but there are many basic things even just in a scientific computing workflow that still feel like they were rushed and they can really take the wind out of your sails.

Agreed, but it's funny that criticism of Julia broadly falls into two categories:

1) Julia doesn't have X. X is critical for modern programming languages, and without X, we should not even entertain the idea that Julia may be usable

2) Julia's feature X is too unstable. It's like they tried to implement too many things in Julia 1.0, and developer time stretched thin. They should have just not implemented all this stuff!

I mean yes, we all would like a programming language that materializes with 1,000,000 developer hours already poured into it, great editor support out of the box, and which is somehow born with 10 years of usage. It's similar to wanting an employee who enters the work force with 10 years of industry experience. Nice, but it's not very realistic.

I agree with everything in this except "You can't extend existing types with data". Data inheritance is implementation inheritance. Don't add it.
For sure. I particularly took issue with:

> In e.g. Python, you are not going to run into types you want to subclass, but can't.

In python, you can only really subclass things that were designed to be subclassed. Subclassing arrays, dataframes, or anything from xarray or dask is explicitly recommended against by those packages. In practice I only subclass the base scikit-learn transformers, Abstract Base Classes, or classes I've written.

In my opinion the most important positive thing Julia has is the Compsci community it attracted.

There has never been so much enthusiasm in oftware for doing physical simulations and correct and stable arithmetics. It made a sizeable dent in the Fortran/C++/Python/Matlab environment physicists were in.

That said even after 10 years Julia has still so many rough edges that I wouldn't employ it for anything outside the aforementioned use case.

Just getting it to Plot something in a headless environment was a pain. Essential utilities like debuggers (!) are external dependencies. Matrix/Vector/Array confusion permeates the air. Ditto for a syntax annoyingly in the middle between Matlab, Python and Fortran.

Given it is already not that young I predict it will never really attract the masses beyond its niche, but it can still kill the remaining Fortran codebases.

It's a little hard to say "after 10 years" when Julia has been at 1.0 for 3 years only. And remember, that's not with Rust's niche of low-level developers, but with a niche of people who are generally not programmers, and therefore much more conservative about their languages!

It's surprisingly hard to get good data about how quickly Julia grows, but it certainly doesn't look like it's plateauing yet. It's just too early to know how far it'll go and where it will end up in 10 years.

If anything, Julia becoming popular with academics makes me extremely skeptical about its missing guardrails. Obviously anecdotal, but I have many years of experience working with academics and statisticians and I know to be wary when they suddenly like a new technology. Usually it's because it makes it easier to swallow errors somehow, or because their friend wrote it and sent them an email about it.
Ha! That's hilarious. Yeah, I've seen some real horrorshows of programming in my field.

I think it's important to realize, though, that academics do have a special use-case when programming. That is, academics don't pick e.g. Python because they are bad programmers and don't know what they are doing, but because Python is a good fit for their needs. I see Julia as an excellent - near-perfect, in fact - academic programming language. That Julia excels at this use case does not mean it's bad at everything else.

Just giving you a hard time... I do think the performance improvements alone make Julia a serious contender. I've seen a lot of valuable engineering time spent rewriting algorithms in C++ for scientists who know Python. To speed up their iteration loop without bringing in performance experts would be great.
One thing I found about Julia which turned me off was the library used for distributions used 64bit floats while that used for neural Nets used less precision, so it's hard to connect the dots there. Also there wasn't a lot of great tooling for RL
If you specify a distribution using, say, Float32s, you'll get a distribution in Float32s. I'm guessing the machine learning example used Float32s so they would better take advantage of a GPU. It's almost always true in Julia that you can combine your choice of numeric type with other neat packages without the author of either one being aware of the other. Want to simulate ODEs in Float32 for speed on GPU, in Float64 for GPU, or if you have an exotic need for high accuracy use something bigger but slower, you can do it.
OP, thank you for this post. I use Julia daily, and it's likewise my favorite language. So I went into this post prepared to be...defensive. But several times in the post I found myself thinking "no! Wait, well, maybe, hmm, urgh, yeah that's not great."

I'd like to read an epilogue or follow-up "so what" post. If Julia is your favorite language but many of these problems seem like some combination of a) unsolvable given the design priorities of the language; b) unsolvable until a hypothetical future 2.0; c) solvable but only with huge resource increases, how do you manage these problems day to day? What do you see as the moderate term future?

Thank you! That's exactly what I was aiming for.

That sounds like a good idea. The problem is that I just don't know enough about compilers, Julia's internals, and how the core dev team works to really forecast the future and know what's possible. How hard would it be to implement caching of native code? A fast interpreter that runs side by side with the compiler? No idea.

Maybe it would still be useful to make a post explaining how I cope with the limitations of Julia. I'll think about it.

I think this is what parent is referring to. A short guide from a power user on coping with those flaws would be invaluable for occasional users.