Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Since everybody is so hyped about Julia, I took on learning it and using it in one of my pet projects. The use case seemed to be perfect for Julia: financial portfolio optimization.

But honestly, it is a royal pain in the ass to use. Mostly because tooling is so crappy (no decent IDE).

For example, I've made these notes on my journey with Julia:

- Juno and VSCode julia is a pain

- Debugging is pain - no watch expressions (but debug> works)

- Works like with matlab (workspaces, designed for the single script use-cases)

- Long registry lookup times (2-5mins) when starting a new session

- No hints from IDE (Juno) on what methods are available for which types

- Ctrl-click navigation does not work to lookup definitations in libraries

- Debugger does not show the full list of elements - there are triple dots in the middle

- Filters and maps are not lazy

- Arrays start at one

- Precompilation times can take 1-2min

- Package management is done as a part of script execution

- Delay (0.5-1s) when processing commands (compilation?)

- Editors (Juno) do not check types at runtime when the information is readily available

- Include() includes (is this PHP all over again?) a file into the script!

- Reuses same REPL between different files

- DataFrames.jl: Transform does nonsense (use map instead)

- DataFrames.jl: No transpose

Obviously, there is a bunch of good things like freakin insane speed and vectorized method calls are awesome, but I struggle seeing myself becoming more producting than Python + Pandas.

It's really a shame that language is strongly and semi-statically typed yet no tooling is making a use of that.



To be fair, most of these are ide complaints, not language complaints.

Much like all development work, language designers are now required to know much more than how to write an effective static compiler, an effective language syntax, and an effective standard library. A working IDE that integrates easily with all mainstream editors, extensions for all mainstream editors, cross-platform compilation for all major environments, a secure and effective dependency manager, a secure and effective build tool, and incremental compilation are all requirements for a language to get off the ground. Honestly, that seems like a big hurdle for one person or even a dedicated team to manage effectively without major funding outside of what is normally present in research grants. Hosting and curation alone for the dependency package system is a costly problem.

Are we as developers painting ourselves into a corner of stagnating pl technology with our expectations that all these things exist in order for us to call a language "good?"


Yes. But only computer scientists are interested only in the language itself. I am an engineer so I have to deal with practical aspects of it.


I'm an engineer. I primarily care about how good the language is at expressing and executing my intent. I've been around long enough to see several tooling fads come and go. I've also been around enough to know that the barrier for delivering quality software is becoming insurmountable, and the additional tooling and infrastructure isn't resulting in projects being more successful, nor being delivered more quickly, nor being less costly than when I started. Teams are enormous now. Software projects are enormous. Deployment requires deep knowledge of multiple hosting platforms and various cloud provider apis at the enterprise level. Available libraries, increasing reliance upon testing, type safety, and better development life cycle practices have had a far larger impact than the ide's I've seen come and go. In my experience, a particular tool has a popularity lifecycle of about ten years. Vscode and lsp will probably be the same. Give me types, good compiler error output, and access to a large universe of libraries with good documentation over relying upon ide api discovery any day of the week and twice on Sundays. The rest is an ever-changing tide of requirements fashion.


Give us some more time, there's just so many things to do and the reliance issues favor getting the fundamentals right first (much easier to switch the debugger UI than the names of functions that'll get put all over the place). We certainly understand the value of good tooling, so just stay tuned and maybe try it again every once in a while to see if it's good enough for you yet. Too much to do, too little time :)


I think this is an important point. What a practitioner can do with a language is influenced as much by the tooling as with the language itself. The implication is that languages should be constructed with as much thought given to the external tooling as to the compiler or interpreter.

Julia in particular is built to be a practical language so, these points are valuable.


I agree with you 100%.

Julia is a language that is half baked for engineering use. Any one who has ever built anything beyond examples and tutorials, something production worthy and used by hundreds of people - they will attest to how immature Julia is.

That's not the fault of the programming language per se... just that it takes 10+ years to get up to speed in terms of tooling and engineering worthiness.

In addition, there are a lot of problems with the language itself some of which are highlighted in the top comment of this thread.


We use Julia in production at RelationalAI. Our cloud hosted next generation knowledge graph management system is a highly performant database and query optimization engine, and it's written 100% in Julia.

We love Julia for the same reasons others have stated here: It's easy and intuitive to write, making it productive to work with for both our engineers and our mathematicians. It's reflection abilities make performance tuning and optimization easier than any experience I've had before. The ability to fine tune the assembly emitted for your hotspots _matters_, and it's straightforward to do in Julia. And for the rest of the code, being easy to write, easy to read, and close to the math are all a big win.


I've built production software being shipped to pharmaceutical companies and used in FDA submissions using Julia (pumas.ai) because it is quite mature in the field of modeling and simulation in comparison to other languages. The stability of the language along with the ability to easily get fast code is the main reason, and it's the reason why if you go to something like the American Conference on Pharmacology (ACoP) you'll hear lots of mentions of Julia.


I've also built several production systems and it has nothing but nightmare. Stack traces are meaningless and there were so many issues with things like ISO Time Zones, HTTP requests (why isn't there a solid http request library? its a mess), Docker problems with compilation, start times were atrocious and still are I think, package management is insane, setting up an internal julia repository is a total nightmare - just go on SO and search for it.

I've lived through this.


Another way of thinking about it is that when switch to a new language, we have to start over building nice tools for it, which seems inefficient. It's like doing a big rewrite.

That's less true than it used to be. Julia wouldn't be where it is without LLVM, and things like VS Code's language server protocol do help. But there is still a lot of redoing things for people who write language tools.


Ceylon had good IDE support when it was 4 years old and nobody used it. That's just an excuse.


That doesn't prove that "it's just an excuse".

It just shows that while IDE support is a factor, it's not the single determining factor.

Ceylon had horrible marketing and advocacy, for starters. And the IDE was Eclipse, at a time that it was getting increasingly unpopular...


Most of his complaints can be solved via a Julia LSP. LSP‘s aren‘t that hard to write.


There already exists a Julia LSP. It's sufficient, could be better though.


>>To be fair, most of these are ide complaints, not language complaints.

The language itself doesn't matter without its ecosystem. This includes tooling, libraries, quality of documentation, the community, and more.


This is why I think its mostly non-engineers commenting about how great Julia is. No one has tried to deploy it prod. Sure there might be exceptions, but if you interview 100 engineers who've tried deploying Julia, a vanishingly small % would recommend it if at all.


I'm not commenting on Julia per se. I'm commenting on the state of discussions surrounding programming languages in general.

> if you interview 100 engineers who've tried deploying Julia, a vanishingly small % would recommend it if at all.

Popularity of a choice does not correlate with a choice being correct. It is a fallacy to evaluate a particular tool's usefulness for a particular job by how popular that tool is. And doubly so when most of a random sampling of engineers includes virtually no one experienced in using said tool. In discussions of virtually any non-popular programming language today, the vast majority of commenters on the language have absolutely 0 experience using it day in and day out for its intended use case. All you have in that discussion are hammer users. To them everything is a nail. And they universally hate any new tool that doesn't look like a hammer, because they can't take the time to learn the new tool. Why would they? Everything is a nail anyway. This is disappointing, especially here, because Hacker News is the place where the concept of using a non-familiar language was expressed as a super-hack for startups. My original reply expresses the conjecture that eventually, all pls will look the same and nobody will be able to develop a language that will truly provide an increase in quality, decrease development or maintenance costs, or improve the reliability and safety of systems the world runs on, because people who evaluate languages actually evaluate them for the tooling that largely gets bolted on after the fact by nonexperts (the lsp server / vscode crowd). There are three lsp servers for python. Only one of them works with pipenv on Windows. Does that make python bad? If python were introduced today, as it was when it first came out, would it gain popularity with all the expectations we place upon a language? No. And that would be a shame. The same is true of Javascript and Java. C and c++ would go nowhere. About the only language that would have made it is Csharp and Visual Basic and Kotlin, because they were written to SELL IDEs and tools.


Well said. Also, the article starts with a litany of praise from a variety of research groups. Some of these are big projects with government funding and serious computing requirements. Julia is deployed all over the place now.


>>Popularity of a choice does not correlate with a choice being correct. It is a fallacy to evaluate a particular tool's usefulness for a particular job by how popular that tool is.

Okay but this is a very engineering-specific mindset. I encourage you to broaden your perspective. "Correctness" of a language choice is more than about the language itself. In most situations, it is better to choose a language that scores 9/10 on how well it fits the problem domain than one that scores 10/10, if the 9/10 language will let you solve the problems faster (pre-existing solutions), with less frustration (good docs) and zero need to reinvent the wheel (good libraries). This is especially true if the 9/10 language will also allow you to recruit more easily due to its popularity.


> The same is true of Javascript and Java.

World would have been a bit better place to live.


> Editors (Juno) do not check types at runtime when the information is readily available

This complaint is really common with people that see types and expect them to do something like TypeScript. Julia is not a statically typed language. The types are not there for a type checker to check your code for correctness.

Instead the types allow Julia to dispatch your method call to the correct implementation for the type of your variable at runtime. This is Julia's secret sauce, and it's the main reason you'll hear about Julia programmers declaring about how composable Julia packages are. I can "reach into your package", and define the behaviour of your functions on my own custom types and then whenever anyone tries to call the function/method with one of my types, it'll just work. I don't need to author a pull request to your package or futz around with anything that you've wrote.

Novice Julia programmers often come in thinking that the type annotations are there for ensuring correctness, but that's not it at all. In actuality, you want to be as general with your types as you can, and by default most parameters will probably be untyped. If you need certain behaviour for the function, then you should probably annotate it, but it's definitely not required.

I'm guilty of this misstep as well, one of the biggest things I struggled with when I was new was using ::Array everywhere, when what I wanted was ::AbstractArray.

> Include() includes (is this PHP all over again?) a file into the script!

Use Modules. Don't fault Julia for you being a beginner and not reading the necessary parts of the documentation.


I am not sure how much I agree with this. I have spent most of my professional career in Python and have watched the trajectory of type hinting in the Python ecosystem somewhat closely.

Python is not a statically typed language and yet type hinting sentiment seems to have gone from: "Why do you want it? Python isn't statically typed?" to "Well, mypy is a useful optional package" to "Let's just support type hinting in the language itself". Which is to say I think there is value to type checking by development tools even in dynamically typed languages.

--

On a slightly unrelated note, Julia seems to be similar to Python when it comes to types; that is to say both appear to be dynamically and strongly typed. But take that with a grain of salt as I don't have any first-hand knowledge of Julia.


Oh I’m not saying that it’s a bad thing to want static type checking. I’m just saying that the type annotations in current Julia are absolutely not for that. It’s for multiple dispatch and for helping the compiler choose optimize your code.

The thing that’s interesting about Julia is that it’s sort of like a verb first language instead noun first. You describe the behaviors that you want by creating methods with one name, getindex, setindex!, etc. that defines the API. Then you can implement that for any type by creating a new method with the same name and a different type signature.

Edit: In fact, I think that over-annotating your methods is probably the number one mistake that new Julia programmers make. Adding a type to the type signature doesn't make your code fast. Adding too many types will restrict your code and it won't work when you think it will because you've told the compiler that this only works with 3-dimensional arrays of type Float64 and you're trying to call it with a 3-dimensional array of type Float32 or Int64.

What makes code fast is type stability, but that's a whole other topic.


> Instead the types allow Julia to dispatch your method call to the correct implementation for the type of your variable at runtime. This is Julia's secret sauce, and it's the main reason you'll hear about Julia programmers declaring about how composable Julia packages are. I can "reach into your package", and define the behaviour of your functions on my own custom types and then whenever anyone tries to call the function/method with one of my types, it'll just work. I don't need to author a pull request to your package or futz around with anything that you've wrote.

That's not a bug, that's a feature. Libraries are abstractions. I get an API and it encapsulates the behavior of the library. That is a nice thing. Being able to modify runtime behavior of internal libraries can lead to insane jumblygoo of code spathetti that would bring the finest programmers to their knees.

I don't want implicit behavior at runtime. I want explicit behavior in case of non-contractual externalities (wrong user input for e.g. at runtime). I want the program to fail so it can be patched.


You still get an API that encapsulates the behavior. This is not like monkey-patching (directly changing the behavior of libraries), but separating the abstraction layers. Every complex enough system will have multiple layers (for example when working on communications, if you're working with the network layer you don't need to focus on the physical layer below or the application layer above). Multiple dispatch allows the library ecosystem to better work in the same way:

For machine learning models we have the layer that handles the low level operation (sums, multiplication), which are swappable (you can have an implementation that runs in the CPU - Julia's Base - and an implementation that run in the GPU - CUDA.jl - and even a TPU - XLA.jl or Torch as backend). Above you have the tracker (the layer responsible for the autodifferentiation logic, which includes Tracker, Zygote, ForwardDiff). And above you have the library with rules for generating gradients (DiffRules, ChainRules), and above you have ML constructs (NNLib), and above ML frameworks (Flux, Knet) and above more specialized libraries like DiffEqFlux.

Whoever writes the ML framework doesn't need to care about the backend, whoever writes the GPU backend doesn't need to care about ML framework. This is not because the person writing the GPU backend patched the ML framework, but because the ML framework legitimately doesn't care about how the low level operations are executed, it doesn't work on that level of abstraction. And the user of the ML library can still see it like a monolith not unlike Pytorch or Tensorflow when he imports a library like Flux, until he wants to extend them and then he will find that they are in fact many independent swappable systems that compose into something more than the sum of it's parts.


I think the previous poster's use of the phrase "reach into your package" was a bit colorful. You're never actually modifying the internal code of a library. You're only extending a generic function from a library to work on your own custom type. So that extension only affects code that uses your new custom type. It's akin to using class inheritance in OOP languages.


> Long registry lookup times (2-5mins) when starting a new session

I'm not sure what you are referring to here. Yes, sometimes after you've installed new packages, the Julia VS Code Language Server has to do some re-indexing which can take some time, but they've improved this and you can still program and use the integrated REPL while this is occurring.

> Ctrl-click navigation does not work to lookup definitations in libraries

In VS Code, F12 (Go to Definition) does work. You can also use `@edit foo(x)` in the REPL.

> Filters and maps are not lazy

Use Iterators.filter or use generator expressions.

> Package management is done as a part of script execution

I'm also not sure what this refers to, but the package manager in Julia is one of the best things about Julia.

> Editors (Juno) do not check types at runtime when the information is readily available

The VS Code Julia extension has a linter that is pretty helpful. It's not perfect, but they're actively working on developing it.

> DataFrames.jl: Transform does nonsense (use map instead)

The new select and transform functions in DataFrames.jl are actually quite powerful and useful.

> DataFrames.jl: No transpose

Transpose is not a generic concept for a table. Sure, it might make sense in specific cases, but in general it doesn't make sense to transpose a table.


>Sure, it might make sense in specific cases, but in general it doesn't make sense to transpose a table.

From my intuition, I don't see anything stopping the function from existing -- it can be applied to any arbitrary table. You probably don't want to transpose your table, except when you want to, but that's true of any function -- I'm can't imagine any scenario where transpose(table)->table would as an algorithm fail (unless I suppose if julia tables include header rows, in which case there's probably no generally correct definition)


> From my intuition, I don't see anything stopping the function from existing

A datatable is (or is isomorphic to and can be analyzed as) a mapping from row numbers to tuples of a given shape[0].

The transpose of table will only be table (a mapping from rows numbers to tuples of a common shape) if the tuples of the starting table were homogenous (every field of the same type.)

This works with, say, matrices where all the elements are numbers; but it fails in the general case.

[0] Yes, I know, Julia defines them as columns of arrays, and columnar organization is ideal for all kinds of processing tasks. For me, thinking about and explaining the the problem with transpose works easier thinking about it in row-oriented form (which is logically equivalent). In column-oriented description, a datatable is an ordered set of columns, each of which is a homogenous array, but if you try to transpose it, each of the columns of the result would be a heterogenous array unless the columns were all of the same type to start with. So, again, it fails to be a table->table function except in the case where the starting table consists of columns of identical type.


No, I'm still not understanding. Here's my thinking:

Scenario #1: If the tuples are the same shape (type, size), it's fine

    [
       (string, int, date)
       (string, int, date)
       (string, int, date)
    ]
transposed:

    [
       (string, string, string)
       (int, int, int)
       (date, date, date)
    ]
Both input and output have tables with consistent shapes (type, size)

Scenario #2: Assuming its legal, if the tuples are differently shaped (by datatype), its weird (but that was true of your original table anyways), but you can still do a valid transposition to produce a valid table

    [
       (string, int, date)
       (int, date, string)
    ]
transposed:

    [
       (string, int)
       (int, date)
       (date, string)
    ]
It was weird to begin with, and it's similarly weird to end with. I can't imagine the output not being a legal table by any rule that does not also disallow the input.

Scenario #3: Similarly to scenario 2, If your tuples are differently shaped (by size), you can still do a transposition

    [
       (string, int)
       (string, int, date)
    ]
transposed:

    [
       (string, string)
       (int, int)
       (date)
    ]
and like Scenario #2, the output is as illegal as the input

In the latter two cases, I don't know what you'd want to do with the transposition (or even its input), but I don't see anything stopping the operation itself from being reasonable/consistent/valid.

Is there another scenario I'm failing to imagine?


> Scenario #1: If the tuples are the same shape (type, size), it's fine

In the row-oriented view: each row of a datatable is a tuple of the same shape (size and order of types as every other row) -- just like a database table. So, if the shape is (string, int, date) for row #1, its that shape for every row.

In the column-oriented view, each column is a homogenous array: every element in the column has the same type.

> [ (string, int, date) (string, int, date) (string, int, date) ]

Sure, this is a fine starting table; in row-oriented, its shape (the shape of every row) is (string, int, date). In column-oriented view, the table as a whole can be viewed as a tuple of shape (string[3], int[3], date[3]) because it has three rows. Cool.

> transposed:

> [ (string, string, string) (int, int, int) (date, date, date) ]

Right, this is no longer a datatable. The first row has shape (string, string, string). So, if its a table, the other two rows must also have shape (string, string, string); but instead, each has a different shape.


Ah!

Ok, that makes sense.


These problems mostly seem to come from trying to use Julia in some kind of visual studio paradigm. The key is to leave the REPL running, I find. Then, with Revise.jl the speed is insane because nothing has to start up; only the changes you make will be recompiled during execution. Also take a look at Pluto.jl.

Edit: By the Visual Studio paradigm, I mean a paradigm where all the stuff is made around visual interactions with the IDE. For example, showing autocomplete which works because the programmer is very constrained in OOP (foo.b completes to foo.bar) and statically typed languages with Java and C# as prime examples.

I think these constraints are made around the idea that programmers are dumb and that it mostly is a distraction from how one actually wants to think about the problem at hand.


> - DataFrames.jl: Transform does nonsense (use map instead)

What is this supposed to mean?

> - DataFrames.jl: No transpose

This is actually going to be fixed in the next few days (https://github.com/JuliaData/DataFrames.jl/pull/2447). Given the limited amount of work it required, it sounds quite exaggerated to mention it as a major limitation of the language.


  - Arrays start at one
Why is this such a big deal? You just change the range of your for-loops from 0<=i<n to 1<=i<=n. Are you using cyclic buffers?


It matters when doing multidimensional index arithmetic. The formulae for ranking and unranking multi-dimensional to flat indexes are neater with 0-indexing than with 1-indexing.


Julia has really nice abstractions for dealing with this. Things for which you might do such calculations in other languages can often be done in a way generic to the number of dimensions, as well as the initial index, using CartesianIndices & friends. And this should be zero cost.


Almost all languages above the C level has nice abstractions for this, but you still sometimes need to do it for various reasons. Basically, whenever the indexes don't matter, then 1-indexing and 0-indexing are equivalently good, but when they do matter, then 0-indexing leads to neater calculations.


OffsetArrays.jl is your friend.

I'm working on a project where indexing naturally runs from -n to n. I kludged the usual index hackery and was so plagued with off-by-one errors that I gave up on it. Then I remembered Tim Holy had a blog post about OffsetArrays.jl and started using that.

Problem solved.

Seriously, the most annoying thing I find about Julia is that the various packages fairly often have "creative" names, that make it difficult discover that they might actually be useful.

YMMV.


> I'm working on a project where indexing naturally runs from -n to n. I kludged the usual index hackery and was so plagued with off-by-one errors that I gave up on it. Then I remembered Tim Holy had a blog post about OffsetArrays.jl and started using that.

Ah, thank you. I've been tinkering around with Julia, and was trying out 2D random walks. Not being able to use a 2 dimensional array and store the position [0, 0] confused me. I ended up starting at X,X (where X > total number of moves) and then got stuck with plotting it nicely, because I wanted the plot axes to show how far it had moved, not X +- how far it had moved.


There are plenty of matrix uses where 1-indexing is more natural. I think the main reason Julia uses it is to be more consistent with Matlab.


Abstraction discovery is a hard problem in general. Good names help, but there's probably more we can do. Tooling finding a common pattern that the abstraction eliminates, perhaps?


I guess it could poke you every time you say `strides(A)`?

Here's a recent example of an upgrade, from code with stride calculations to a more abstracted version, which is generic to offsets & number of dimensions:

https://github.com/JuliaLang/julia/pull/37367/files#diff-29c...


Fair enough. But is this a common enough occurrence in the life of a programmer that it's worth being a religious extremist about?


No need for an inquisition. In both Fortran and Julia you can set your index origin to be whatever works best for the problem you are expressing.


It's in a list of annoyances, together with 16 others. I don't think anyone is being "a religious extremist about" it...


In Fortran, you can start the index from any number you want. A(-10:-3) is a completely valid slice or full array declaration, so are A(0:7) or A(1:8). and this feature is absolutely useful in scientific computing.


I also didn't think it was a big deal - I write a lot of lua, and I love lua - but every time I have to do anything involving modulo maths and arrays it's a pain in the ass.


Julia makes it easier for example with functions that handle mod in the context of 1-indexed arrays (if you don't want to use OffsetArrays).

https://docs.julialang.org/en/v1/base/math/#Base.mod1


Well, that seems cool, but isn't indexing from zero simpler?

I don't really remember if zero-indexing was a big deal when I was learning to program. Are there big advantages for non-programmers? I figure that's why Lua went the 1-index route.


>I don't really remember if zero-indexing was a big deal when I was learning to program

And neither is 1-indexing even though people are always complaining about it. I kinda like when indexing from the third element to the seventh element to be just 3:7, instead of 2:6. and the last element to be length(x) instead of length(x)-1. And that use case is much more frequent to me than creating circular buffers on an array. And in Julia you can just use begin:end as well, or any iterator, it's really overall a non-issue for me.

Not sure about Lua, but in Julia (and Matlab, and R) is just because they actually have vectors/matrices types that have a convention that predates even programming, while it makes sense for languages that an array is basically a memory offset (that maps to a pointer arithmetic logic) to start in 0.


Array should start from any index scientist wishes. That is how it is done in Fortran.



Dijkstra has a certain tone. He can make his opinions sound almost like a mathematical proof. But when you dig into it, he just says 0-based is "nicer".


The points he makes are so extremely minor... You could just as easily say that natural language and mathematical convention are index-1.


I never understood the fascination with preferring "the element at zero offset from the start" to "the first element" - and I don't think djiskarta makes a compelling argument.


Edit: just learned about OffsetArrays.jl - ok now that's really cool. Keeping comment for context.

> - Arrays start at one

Oof. Big turnoff for me. For some reason, this particular context switch really grinds my gears. All languages I use (except bash, which grinds my gears) use Dijkstra-style array slices: python, go, c/++, js. I'm sure it makes it easier for Matlab converts.

This, plus the mentioned weaknesses with libs like http, grpc et al, IMHO will relegate Julia to many years of just being wrapped by other languages. To avoid that, I think they should be thinking about continuing to woo more of the engineering crowd - which to their credit I think they've done pretty well so far.

https://www.cs.utexas.edu/users/EWD/transcriptions/EWD08xx/E...

https://github.com/JuliaArrays/OffsetArrays.jl


They’re making the language mostly for statisticians, mathematicians and scientific programmers, where it makes sense to have arrays start at 1. Why should they cater to whiny engineers who can’t deal with anything they aren’t used to?


Arrays start at 1!? What Joy! Maybe I can try this language!




Consider applying for YC's Summer 2026 batch! Applications are open till May 4

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: