Will Julia Replace Fortran for High-Performance Computing?
Fortran has been the optimal tool for numerical heavy-lifting for such a long time, that I tend to be quite skeptical about the idea of replacing it. However, the story might be different this time, with Julia.
As is well known, every decade or so, some computer scientist comes out with an opinionated piece titled “Fortran should be abandoned, and replaced by X’, and the only thing that gets replaced (at least for numerical computing) ends up being ‘X’. This is what happened time and time again.
I have written a post about Why is Fortran still used and I believe there are many reasons for its popularity in the HPC niche. In a few words, Fortran has adapted over the decades, it has even introduced significant innovations such as Coarrays, and overall, continues to serve the scientific computing community very well, especially in HPC, as a specialized programming language for numerical heavy-lifting.
Of course, we also have to consider several other factors, such as the impact on programmer’s time, code maintainability, reusability, the existence of an open-source community, and so forth, where Fortran has some undeniable weak spots.
I believe that Julia pretty much supersedes Fortran in each of these aspects, including Fortran’s core strengths in HPC. Let’s dig into this.
Julia is so performance-centric as Fortran or more
Personally, I’m even willing to sacrifice a tiny bit of performance if I get to write beautiful, concise code in return. Especially, if I can also run the same code both in an interactive, fast-prototyping mode, as well as in production, with negligible changes.
However, I found out that Julia is just as fast as heavily optimized Fortran code linked to Intel’s MKL. See my post about a Julia vs Fortran vs Numpy performance test. Interestingly, the Julia’s JIT compiler is doing just as good as gfortran, or even better in some cases.
Also, Julia allows you to go even to low-level hardware-dependent optimizations. This goes against one of the main design characteristics of Fortran, namely, to keep the language, so to say, restricted to the math, and let the compiler do its job at optimizing the code for each architecture. Julia, on the other hand, supports C-style low-level optimizations via various libraries, such as LoopVectorization.jl, which provide some level of abstraction to the various hardware-specific special instruction sets that can be used to optimize loops.
Julia’s array syntax builds upon and improves that of Fortran and Matlab
One of the foundational characteristics of Fortran was native support for multidimensional arrays. In addition to that, Fortran introduced the array-slicing syntax which has been largely picked up by popular mathematical languages like Matlab and many others.
Python’s zero-based indexing can create a lot of confusion. Of course, there are many arguments for supporting zero-indexing, and it boils down to a matter of preference. But Julia’s decision to stick with the convention put in place by Fortran, Matlab and most mathematical textbooks looks beneficial.
In addition to that, Julia incorporated much of the Linear Algebra syntax introduced by Matlab, like the backslash operator for “solve”, native support of matrix multiplication with , the ^ operator for power instead of Python (and Fortran’s) *, and so on.
Julia has introduced another striking innovation, which is the support of Unicode characters in code. For example, you can use variables such as \( \theta \) directly in your code.
Other innovations are borrowed from Python, instead, like comprehensions
[ 0.25*x[i-1] + 0.5*x[i] + 0.25*x[i+1] for i=2:length(x)-1 ]
sum(1/n^2 for n=1:1000) 1.6439345666815615
In sum, Julia has incorporated the most attractive syntax originally introduced by Fortran, and it has improved upon it substantially.
It’s much easier to write and refactor code in Julia
In addition to the convenient syntax, there is yet another reason which makes Julia easier to use than Fortran. And that is interactivity. Additionally, code written in Julia is also a lot easier to refactor than Fortran code.
In Fortran, every single function must have a very large number of lines of code, as absolutely every single variable’s type and size has to be declared by the programmer.
The reason for this is that Fortran had a certain feature in the past, according to which, by default, all variables beginning with the letters i, j, k, l, m, and n would be treated as integers, while all other variables were assumed to be real numbers or arrays. This seemed to be convenient, but later, the ‘implicit none’ statement to inhibit this feature was introduced and constitute the actual best practice.
This has a strong impact on the effort take it takes to refactor code, and consequently, on the willingness of programmers to do so. This introduces technical cost, as the option at any given time is to either clean up the code now or pay for costly errors later.
Julia, on the other hand, has support for both implicit and explicit typing. Implicit typing can be used for fast-prototyping, and explicit typing is required for performance. This gives the programmer significant room for experimenting and testing, and only later, a few extra lines of code are required to optimize performance-critical sections of the code. Not every section of each code has to be optimized in this way, though.
Technologies like git make backward compatibility less concerning
I remember that the last time I was considering trying Julia, they had just released a new version of the language that didn’t offer backward compatibility and broke many people’s code. As a consequence, I decided to ignore a language I thought, had so little consideration for the long-term value of its programmers’ work.
But several years have gone by since my last consideration of Julia, and the current version 1.6 (at the time of writing this) seems quite stable. In any case, trying new things always comes with some risk, and at least Julia’s approach to avoiding the Python2/3 disaster is that of supporting at least two adjacent versions simultaneusly.
I’m also optimistic about present-day technologies like Git, where a robot could perform pull requests with automatic version updates. It is also good practice to have tests (and maintain them, something which I tend to fail to do more often than I would like to acknowledge). So I believe the issue of backward compatibility will be less concerning over time, for anyone following good programming practices.
Juia enjoys substantial network effects of a thriving open-source community
Julia has a very active ecosystem which is a guarantee of innovation. An active open-source community provides:
- Packages for users and feedback for developers.
- Ample documentation and learning resources.
- Public relations to attract new users and reinforce a positive trend.
Fortran has neither of these.
In particular, on the public relations side, Fortran is still referenced with mainframes, punchcards, goto statements, and UPPERCASE, regardless of having moved way beyond all that several decades ago.
It can be argued that some of these issues are being addressed by the development of the LFortran interactive compiler, and the vendor-neutral Fortran-lang.org community.
However, it is well known that there are network effects of communities, with several self-reinforcement trends taking place. Julia has already attracted thousands of package developers and supporters and has a definitive lead in this regard.
After carefully considering Why is Fortran still used, which was actually a reflection on some of my past experience, and some recent testing I done regarding Julia, I believe that overall, Julia is a move in the right direction. I will very likely be adoping Julia for some (or even most) of my future projects.
For as much as I would like to see a truly modern Fortran, backed by a strong open-source community, with substantial tooling and a strong commitment for enhanced programmer’s productivity, I believe we will be referring to such a language by the name of Julia in the not-so-distant future.