I find Julia to be a wonderfully expressive language to write in, without sacrificing any speed. The abstractions allowed me to write less code (especially boilerplate), and maintain cleaner code structure -- mapping to my understanding of the problem. Feels much friendlier than Python to me, but YMMV. (My experience basically revolves around prototyping various numerical/ML algorithms for exploration and understanding, and not the kind where you just call a library to solve a task. Projects mostly in the range of 20 to 2000 lines of code. Having used both Python and Julia for such tasks, I lean towards Julia when I have the choice)
A couple of my previous HN comments on Julia's indexing: https://news.ycombinator.com/item?id=15472933 https://news.ycombinator.com/item?id=15472933 and https://news.ycombinator.com/item?id=15473169 https://news.ycombinator.com/item?id=15473169
Plus, I found it exciting to read community discussions for a language growing towards 1.0, to understand the different approaches that were considered, and why certain choices were made. From what I've seen, the whole development process was quite transparent, and the developers have always indulged sincere questions/suggestions from participants, dealing in concrete examples instead of sweeping generalizations and polemic. I don't know what standard to compare this to, but I've enjoyed the experience.
As somebody who appreciates Julia, my opinion is - probably not. That is, unless you want the opportunity to create a killer library that shows how the language features map well to other domains.
But, I think a lot of people in scientific computing are tired of the typeless mess that Python/Numpy/Scipy code-bases evolve to be. And for those people, I think it has a lot of merit.
At the end of the day, the language was designed to fill one major gap. A lot of time and effort in R&D is spent either; architecting sane C++ memory models, or reverse engineering existing Python code. Alternative well performing and safe languages like Java simply are not fast enough - to get the features of the modern CPU, you need to be native. And a side-note, MATLAB cannot usually be ran in a production environment.
What do you mean by production environment in the context of academia / R&D?
Usually “production” in those contexts means running on a cluster or supercomputer somewhere. That, or code being run on a machine not controlled by the developer by users who do not write code but just run a pre-existing program with different inputs. That’s how I (and colleagues) typically use the term ‘production’ in the academic/research environment that I work in. The issue with things like MATLAB in production is the lack of a license on the machine you want to run on - often people have it on their workstation, but if you get time at a supercomputing center or department cluster, odds are your local license doesn’t translate over to the system you want to run on.
There are R&D departments outside of academia.
But in both commercial R&D and academic R&D, some code really needs to live on for future people to benefit from it. It's just not a good use of research time for people to re-write everything from scratch... every time.
Having spent years working with numpy and Cython, then switching to Scala for years as well, I much prefer dynamic typing.
Strong type safety is mostly just a waste of time.
One thing that makes Julia cool is that adding the types improves performance, but you don't have to add them if you don't want to.
Ohhh… I really disagree; I find that strong typing allows me to get the compiler to check that the work that's going on in the various branches of my code is at least allowed - even if it's wrong. I wish that my test cases really did test all of these corners, but realistically I just don't believe that I am good enough at writing test cases to get everything. From another perspective using strong typing like this saves me lots of time in terms of writing finicky test cases. I'm not saying that dynamic typing is wrong - in fact it is brilliant in terms of not having to write reams and reams of dangerous and maintenance heavy boilerplate!
I’ve used a lot of functional programming unit test tools, and I’ve never seen any of them live up to the hype of checking corner cases in an automated yet comprehensive way.
The marketing pitch for that is always something like QuickCheck in Haskell, where e.g. reversing an array should be its own inverse function and you can auto-verify this like it is a law across a bunch of cases.
The problem is in real life unit tests, nothing has any laws like this, and it’s just a bunch of bizarre case-specific business logic and reporting code. The concept of a corner cass is a semantic one, and the definition of what inputs are possible to a given function will change and have constraints from the outside world that not even the most expressive statically typed language will easily let you encode into the type system.
Combine it with the fact that your colleagues have variability in their skills too, and often won’t make good choices with type system abstractions to represent business logic, and then all that costly extra boilerplate code for specifying types, creating your own business-logic-specific ADTs, adding privacy modifiers, templated or type classes implementations...
...it just becomes a big pile of garbage liabilities for what turns out to seriously be no benefits over dynamic typing.
Even in the static typing case, you’ll end up with tons of runtime errors causing you to frequently revisit assumptions in the unit tests. You’ll just have a harder time refactoring large pieces of code that are wedded to particular type designs and you’ll have to sit and wait on the compiler to try every change (this can be hugely bad when the system has components needed for rapid prototyping, interactive data analysis, or other real-time uses).
I’ve really seen a lot of corners of this debate play out in practice, and static typing beyond extremely simple native types and structs (basically C style), really offers nothing while being a huge productivity drain. The claims that it actually helps productivity because the compiler catches errors and forces more correctness just turns out to be false in real code bases. You get just as many weird runtime errors and just have a harder time debugging or rapidly experimenting with changes.
Since you seem to have the same quarrels with MATLAB as me, have you figured out a good way to run it in batch mode, without having to open the interactive console?
Both Matlab and Julia can be run in batch mode, without going to the REPL.
I empathize with you, but I don't have any tips. Any requests to me to make MATLAB part of a distributed computing were given a pretty hard 'no'.
I've only been learning for about a week, but I think if you're a nerd for language design, you will appreciate it on an aesthetic level as a very tight design around a powerful concept. Common Lisp also has multiple dispatch, but I feel the integration of it into all the nooks and crannies of Julia really pays off. Julia's performance doesn't appear as a side effect of building on the LLVM or because they over-optimized the core, as it does in many young performance-oriented languages. Instead, it appears as a tangible benefit of a multiple-dispatch oriented design that makes it easy to add information to the system to improve performance without compromising the clarity of a sketch.
I have often felt that there are many discontinuities between "pretty" Haskell as it is taught and pragmatic Haskell. I haven't used Julia enough in anger to say it for sure, but I see in the way it works great potential for the pragmatic code to be as beautiful as the high-level and abstract code.
For a long time I have felt that Haskell represented the most mathematical language. Julia really shows that there are other ways of building a mathematical language with taste and style. It's oriented to practitioners and applied math folks rather than computer scientists and pure mathematicians. I have enjoyed seeing the differences between these systems quite a bit, and I think Julia has a bright future as a practical, daily-use system for science.
Our nnz is certainly far greater than 2 billion. The matrix size is around 150 million rows by around 1.7 million columns. We just accumulate the count with a python integer.
I don’t know what you mean by “that’s just numpy” though — since even if this flows through other systems, tracking it at the source in numpy would be obvious.
“Static types help rule out these cases..” — I just disagree. That is what’s advertised, but it’s just not true. Years of working in Scala for very heavy enterprise production systems has made me realize it’s a very false promise. There are actually remarkably few classes of these errors that are removed by static type enforcement, and perfectly good patterns to deal with it in dynamic type situations.
If static typing was free, then sure, why not. But instead it’s hugely costly and kills a lot of productivity, rather than the promise that it improves productivity over time by accumulating compounding type safety benefits.
I think a good rule of thumb is that anything that causes you to need to write more code will be worse in the long run. There’s no guarantee you’ll actually face fewer future bugs with static typing and visibility noise in the code, but you can guarantee it adds more to your maintenance costs, compile times, and complexity of refactoring.
I guess Python’s gradual typing is a good compromise, since you don’t have to choose between zero type safety or speculative all-in type safety where the maintenance overhead almost always outweighs the benefits (rendering it a huge and unreconcilable form of premature optimization).
You can only add it in those few, rare places where there is demonstrated evidence that the static typing optimization actually has a payoff.