Hi Ondrej,
Thanks for your efforts to learn about Julia. I wonder whether your lfortran could benefit from Julia? Why not drive the interactive part from Julia? You just translate fortran to llvm, and then run from Julia.
Hi Ondrej,
Thanks for your efforts to learn about Julia. I wonder whether your lfortran could benefit from Julia? Why not drive the interactive part from Julia? You just translate fortran to llvm, and then run from Julia.
I think LFortran can greatly benefit Julia in multiple ways. Right now we are concentrating on delivering a minimal viable product (MVP) to compile some simpler Fortran codes (MVP: Roadmap to compile the SNAP project (#313) ¡ Issues ¡ lfortran / lfortran ¡ GitLab), but after that here are some ideas:
We plan to write a Julia backend (besides the LLVM and C++ backends) that can translate Fortran to Julia. So for people that want to move away from Fortran or just take some Fortran code and use it as a basis and continue development in Julia, this should work great.
Julia wrappers: for codes that should stay in Fortran, but just being usable from Julia, the LFortran compiler should generate good wrappers (with native Julia arrays, etc.). So when you are in Julia, letâs say the REPL, you could call any Fortran function / module directly, and LFortran takes care of the details.
Julia to Fortran: in order to use Julia libraries from Fortran, it would be nice to call them from Fortran easily. This requires some brainstorming, but I think it is possible at least for a subset. LFortran would infer from the way you call a certain function in Fortran how it must be called from Julia.
(The same for C++ and Python)
Hi and many thanks for interacting so nicely with this community! I hope you donât mind but I just have to ask you: why are you doing this? I understand the motivation for keeping old codes running and developing features in them instead of rewriting them from scratch, but do you actually advocate Fortran for new projects? I ask because to my mind, julia is a strict improvement on Fortran in every aspect (at least at the language level; some tooling is still missing), so Iâd be interested to hear your point of view.
(FWIW, you could describe julia in the reverse way as you do: âhey, this fortran thing is fast and has first-class support for arrays and complex numbers, shame itâs so low level and every function has to be twenty lines long, letâs simplify it a bit, and make it interactive while weâre at it. Oh and to do fast untyped math we basically have to do multiple dispatch, so letâs build the language around that.â)
@antoine-levitt thank you.
(Yes, good idea to do it both ways with the language comparisons.)
Regarding why I do this, we tried to explain our motivation for LFortran in particular in the following two blog posts:
I think they answer most of your questions (yes, I advocate Fortran for new projects). The motivation and history behind fortran-lang.org is described in my blog post here:
Fortran is also missing tooling, but we are working on fixing that.
My personal view is that I have no doubts that Fortran has not reached its full potential yet, so itâs hard to say how things would look like once tooling is improved, there is a community (fortran-lang.org), package manager (fpm), standard library (stdlib), LLVM based compilers (LFortran, Flang, Intel ifx, âŚ), it works interactively (Jupyter), etc. Regarding speed, if I was designing a new language that makes it easy for compilers to optimize, it would probably be something like Fortran: as much mathematics in the language itself. Once LFortran matures, I plan to look at that more closely. If anyone of you have some code or benchmark that is faster in Julia than in Fortran, let me know and Iâll have a look.
I guess that makes sense: if your criterion for designing a language is absolutely zero compromises on speed ever, then probably you canât do much better than Fortran. The problem with this is that not all parts of an application is performance-critical, and at one point youâre going to write a parser, architecture a large application, pass functions around, call other libraries - and then the trouble starts in Fortran. Julia has a different compromise: it makes it possible to write as-fast-as-fortran code, but it doesnât force you to do it all the time - basically you can switch from writing python-style code in one function to write fortran-style code in another. As a result there are a few performance gotchas, but those are easily learned and worked around. Regarding speed, the performance of optimized julia and fortran is basically equivalent - it comes down to differences in compiler or similar considerations.
Yes, the devil is in the details. I will have more to say on this performance topic in about a year, right now I am still focusing on basic compilation (just generating correct LLVM code).
I donât want to spread too thin right now, but down the road I would love to have side by side comparisons of Fortran, Julia, Python/NumPy, C++, etc. I have done this for Fortran/Python about 10 years ago here: Python Fortran Rosetta Stone â Fortran90 1.0 documentation, but it would be nice to add more languages, modernize and also do more complicated examples.
Except one.
Being able to produce small (or not that small) stand-alone executables. IMO this is a major feature that non-interactive language users have troubles to comprehend.
Many things I like about fortran.
One is intent(in)
and intent(out)
, another is writting out all variables explicitly.
This is why so many autodiff scientists like using it to try out new ideas (such as Tapenade).
A different perspective.
I think âPython but fastâ is a good way to explain Julia to programmers who have never heard of it. The main differences are
speed - fast enough that it doesnât need C extensions. CPython is notoriously slow on many tasks. I think speed is the biggest difference between CPython and Julia, because it avoids needing C extensions in many cases. The original âPython but fastâ is PyPy, whose speed has been hampered by maintaining compatibility with the old CPython C-API; recently the Hpy project has started work on replacing that API. I suspect (without evidence) that if PyPy had been available when the scientific Python stack was being written (around 2000), then Pythonâs scientific libraries wouldnât need so many C extensions either, and that stack couldâve been implemented with much more Python and much less C.
multiple dispatch - has some ecosystem effects like encouraging more array types. I donât think this has as much impact yet as it could, mostly because Julia lacks interfaces. Without an interface definition system, APIs are inconsistent, unreliable, and have unclear semantic relationships. I donât think âautomatic interoperabilityâ is scalable in practice under an informal manual model. This is why Clojure has Spec and why Python has protocols/zope interfaces/ABCs.
macros - Allow more concise syntax in some cases. Python might get these soon though they often do more harm than good. Juliaâs hygiene is complicated.
uniform packaging story - Having a single declarative packaging tool makes it easier to statically analyze and manipulate packaging metadata. Python has good packaging systems now with Poetry and Conda, but thereâs a ton of existing code that doesnât use systems like these.
Python and Javascript are maybe the most-used languages in the world, so it makes sense to compare to them when possible. But the comparison is also pretty natural.
On the similarities. Iâll pick some features and compare Julia and Python to alternative choices other languages have made.
Easy to start. print("hello")
just works. Compare to Java which needs public static void main(String[] args)
which can overwhelm a beginner before they even start.
Significant focus on scientific applications. Contrast with Common Lisp, a fast lisp with a smaller scientific user focus.
Syntax. Mostly M-expressions but with some reserved keywords like continue
and while
. Contrast with Scheme, which uses S-expressions only.
Built-in repl. Contrast with C++, which is often used in scientific applications but doesnât have a repl.
Dynamic typing. Values are tagged with their class at runtime. Contrast with C++ again.
Static type annotations. Both have a system for optionally declaring types which helps with reliability and documentation when used. Contrast with C++ which has required static annotations and Clojure which doesnât have any.
Mutability. In both languages, mutable state is widely used. Contrast with Haskell which mostly disallows this.
Ability to evaluate code as data. Julia has syntax sugar :(a + b)
which can be written in Python as ast.parse("a + b")
. Since the distinction between compile time and run time is fuzzy under JIT compilation, these are more similar than they look. Python also has builtins compile()
and eval()
. Contrast with Go which doesnât have this.
Program distribution. Run under the preinstalled runtime executable. Contrast with Go which makes static executable binaries.
Strings. Strings are sequences of code points. Contrast to Swift which uses extended grapheme clusters.
Partial extensibility. Users can define the value of the booleanized version of their expression, but canât control the behavior of if
or overload dispatch. Contrast to CLOS which lets users control dispatch.
Garbage collection. Allocated space is collected automatically by a garbage collector. Contrast to C and Rust which donât have this.
Batch garbage collection. Latency can be inconsistent under this model, which is relevant in some applications. Contrast to Go, which considers GC latency an âexistential threatâ and designed its garbage collector to minimize latency.
Hard to control low-level performance-sensitive properties. For example, there is currently no way to disallow allocations in either language. Contrast to C, which makes allocations more explicit.
Unrestricted use of foreign objects. You can access private data on any object. Contrast to Java which disallows this.
All in all, I donât think Julia in 2021 is as different from Python as some users might â except for tuned speed â but thatâs not necessarily a bad thing: Python is popular for good reason. Julia is immature in comparison and hasnât yet figured out its story on a lot of things, such as traits and interfaces, which are promising future directions (among many others). Juliaâs capabilities are likely to mature over time in ways we havenât seen yet.
Julia lets you turn off/on GC using gc_disable()
and gc_enable()
. This can be really useful in some performance sensitive cases.
Python has gc.disable()
for the same.
I agree with this; also multithreading, debugging and profiling lags behind Fortran. This is what I meant by âtoolingâ.
i thought multithreading was easier in julia, when i talk to people who use fortran they mention mpi and other demons.
Almost, but thatâs not quite there. That statement makes multiple dispatch seem like an addon, while if you really look at the design of Julia, multiple dispatch is the sole reason why it is able to look dynamic while compiling to fast code. Itâs very integral to the whole story as to how the compiler is able to optimize the way it does, and the story would be significantly compromised without that mechanism.
Thatâs partially why there have been a few billion dollars into Python to only get a few JITs that are 30% faster: you simply cannot directly match the semantics of Python and make everything compile to fast code. You have to tone down some features and change some of the dynamic behavior into statically-definable behavior (i.e. multiple dispatch) if you really want to be able to map it all down to something statically well-defined for most use cases.
MPI is not for multithreading, itâs for distributed computing. You can still use MPI in Julia just as in fortran. Multithreading in julia is there, but itâs (as of now) slower and less well-integrated than OpenMP.
But is OpenMP a part of Fortran language? I know itâs widely used, battle tested, and fast, but I thought itâs more of an extension/library, than a part of the language per se. Does Fortran have composable multi-threaded parallelism as a part of the language (similar to Base.Threads.@spawn)? Or is it maybe available as extension in OpenMP?
That is a good point. However, I share the feeling with @antoine-levitt that resurrecting Fortran after the fact that Julia exists seems like a lot of energy put into the wrong places.
I am trying to be as impartial as possible here, but I will certainly fail this objective without realizing it (we are all biased). In my opinion, fixing the executable size in Julia feels like something that could be done somewhat easily by experienced Fortran developers and LLVM experts, whereas adding multiple-dispatch and other nice features of Julia to Fortran doesnât seem easy nor productive. The Julia ecosystem is so smooth already that is hard to beat in feasible time (documentation, tests, binary distribution, domain specific packages)
Anyways, welcome @certik to our community. I hope both communities thrive in their own ways, and that human effort is put into the right places.
Itâs not a part of the language, but itâs supported by all the major compilers, so whatâs the difference? I donât know how composable it is, but juliaâs fast ubiquitous composable multithreading is not exactly a reality right now (thatâs not to say it wonât be at some point in the future; I was just pointing out that right now juliaâs multithreading is in flux and still lags behind openmp in several ways)
That is a good point. However, I share the feeling with @antoine-levitt that resurrecting Fortran after the fact that Julia exists seems like a lot of energy put into the wrong places.
To be clear, this is not a zero-sum game: all positive energy is always good, and certainly everyone benefits from having a better Fortran. It makes sense to support âlegacyâ languages and codes, just as it makes sense to develop new tools. But I definitely wouldnât recommend anybody to use Fortran for any new project, unless the main objective is interoperability with existing code base, or in very conservative environments where using anything less than 10 years old for serious purpose is a bad idea (Iâm not saying this pejoratively, thereâs sometimes good reasons for this).
I have the impression that even the developers share this view, but I donât completely get what is missing from what is implemented already. From a syntatic point of view, using @threads
or even packages as FLoops
is much easier and cleaner than using OpenMP.
@threads
has a known overhead if applied to parallelize fast computations (is that what you and others mean by it is not quite there yet?). FLoops (as an example) solves this for at least quite a few problems I have faced.
My experience, as a user of those tools, is that using threding in Julia is already at least much easier than using OpenMP. But it is likely that my usage is very narrow and I donât capture what is missing.
but itâs (as of now) slower
Can you provide an example? Itâs interesting to have some numbers to understand the size of the problem.