What is the advantage of Julia over Fortran?

I don’t think automatically changing rand(100) into something like x = zeros(100) combined with a later rand!(x) will ever be done automatically. The reason is that while this transform may be “obvious” for people in this case, for the compiler it may not be and on top if that, the compiler has to be able to do this in the general case, which is going to be much more complicated than this little loop here.

I think even with the immutable array optimization PR, the API would be split into “give me readonly memory” and “give me writable memory”, in which case the compiler is free to transform the former into the rand! version because from the semantics of the original code, there’s no danger in overwriting it.

I also think that such an automatic transform would make it much harder to reason about the performance of some piece of code, because it then relies on an optimization that may not always be applied, and coming up with simple rules for when it is applied is potentially very hard.

1 Like

I agree that Julia takes compatibility and reproducibility very seriously, but I think that it is honest to say that Fortran also does it, and to a degree not seen before or after.

Without entering in a useless discussion, I want to clarify some things:

I agree. And Honestly, I will be more happy if Julia would never move to 2.X. This is basically what Fortran does.

¿What happens with your binaries if we move away from amd64? The statement of different compiler version is just wrong. I have several versions of gfortran installed (no containers). FreeBSD even allows you to get them from the package manager.

No intention to spread FUD. And good to know that these are the intentions. Sometimes I read long discusions like this (rename `angle` to `phase` (or something else) in 2.0 · Issue #35538 · JuliaLang/julia · GitHub) and I get really worried. These are the discussions that I do not really understand. If you do not like angle(z), or even if we all agree that is an unfortunate name, I would be very happy if it is just deprecated, but that it keeps working. I certainly would not understand making a sed -e "s/angle/arg/g" for trivialities.

It is very good to know that Julia will live with the decisions made in the past (even if they are suboptimal), and only produce breaking changes if they bring improvements impossible to obtain by just adding things to 1.X.

Fortran code does not depend on many external libraries (maybe BLAS/LAPACK). The rest you code it yourself with only the standard… Most of the timees if you use some library you have to compile it yourself, which has the advantage that you have the complete sources of your code.

It would be great if there were a way to dowload and tar the exact sources of a project and that julia progresses in the direction of making possible to generate an executable from these sources (I know that there are works in thiss directions). If even to Julia 2.X, you could pass a command line argument (-v1) to geneate the executable of Julia 1.X that would be a very big step in my opinion.

I have taken a 30 years old fortran 77 code written for a CDC Cyber out of a magnetic tape. Passed one of its functions to a minimization code using genetic algorithms in fortran 2003 and everything compiled (and worked correctly) without a single line change in a Linux 64bit machine. I think that one has to acknowledge how amazing and good for scientific work this is.

4 Likes

I don’t think that’s 100% correct. Fortran 77 (fixed) syntax is incompatible with Fortran 90+ (free) syntax. While most compilers are able to digest both, you need to tell them which format to use, for example by using the right file extension or an appropriate compiler flag. While the end effect is that with a recent compiler you can likely compile both Fortran 77 and 90+, that doesn’t mean they’re completely compatible. That’s kind of like if Julia 2.x had also the possibility to run Julia 1.x code with a switch.

1 Like

I think that this is not accurate. A compiler that supports the fortran 77/90/03/08 standards must allow you to produce a single executable with one file in fixed fortran that contains functions in fortran 77 and another file in free format that contains a fortran 90 module. (obviously you cannot mix fixed/free format in the same file, but these different formats can be part of the same code).

Note that this is very powerful… my routine for integration using Simpson rule was written many years ago. Today I can call this routine in a fortran 2008 program that uses paralellization with coarrays. I do not need to “port” my old codes.

To achieve this in Julia, it should be possible in Julia 2.X to write using MyModuleInV1, and that it works without changing anything. If this is achieved, that would certainly be great, and basically equivalent to what fortran does (adding new functionalities, without breaking compatibility with previous standards). I would be extremely happy if something similar to this approach is taken: my current code would be perfectly portable to v2, without a single change.

1 Like

What is not accurate in what I said? Compilers build intermediate object files, at which point the originating source code doesn’t matter anymore, and they then combine the object files into the final binary product.

Your observation is incorrect. Fixed-form vs. Free-form is not about syntax, it is about form or format. You can write Julia on a whiteboard or carve the letters into stone. In either case, it is the same code. Similarly, you can write Fortran 2018 via punch cards, in fixed-format or free-format, or write FORTRAN66 in modern free format. Remarkably, a language of the era of punch cards has remained backward-compatible for seven decades, while Julia, only ten years old, is already discussing mitigation strategies for the impending damages of a Julia 2.

1 Like

This is not accurate:

Fortran 77 is 100% compatible with Fortran 90. You can call your F77 functions inside a F90 program without changing a single line. As commented below free/fixed format is not about F77/F90.

I insist in this point: Full compatibility means that in your future Julia 2.X program you can using MyModV1 and that everything works. If the design of Julia 2.X takes this seriously as a priority I would be extremely happy. This is basically what fortran has achieved during the last 50 years (in _CRAY machines, clusters, personal computers, laptops, mac, linux, windows, etc…). It is absolutely amazing, and I think that it has a lot to do with why fortran has the place it has in scientific computing. It would be great if Julia (as I said, an amazing language that blew my mind when I saw it), takes this experience very seriously.

1 Like

I think there are some mixups here. Are you @shiroghost talking about

  • compiling Fortran 77 code with a Fortran 90 compiler

or are you talking about

  • calling into already compiled Fortran 77 code from code written with Fortran 90?

While subtle, there is a difference, because I don’t think you can use the exact same compiler (i.e., that’s what the flag mentioned by @giordano would do, switch to a different compiler internally in the compiler executable) to compile Fortran 77 and Fortran 90 to a binary artifact (which you could call from anything that understands ELF files on linux, irrespective of the original language the code was written in).

Syntax → form, fair enough, but then what I’m trying to say is that once something is compiled down to binary the originating source code doesn’t matter anymore. You can also call a Fortran 77/90+ or C functions compiled into a shared library inside a Julia program, does that mean that Julia is compatible with (in the sense it has the same syntax as) Fortran/C (which is what @Sukera just pointed out above)?

All fortran compilers that I know, can compile fortran77. For example:

gfortran file1.f77 file2.f90 main.f08 -o analysis.x

Works perfectly, with file1.f77 being a bunch of functions written in fortran 77 35 years ago (in fixed format), file2.f90 being a module in fortran 90 written 20 years ago, and main.f08 being a fortran 2008 main program that uses paralellization via coarrays.

The main point is not that this works for the special case of gfortran. The point is that it must work for any compiler that claims to support the F77/90/03/08 standards.

Not lfortran, according to its documentation which mentions only Fortran 2018 (but I never tried it myself)

1 Like

If that is the case, it would be a 1.X. Fortran is “1.X” and will will always be apparently. This has its virtues, but it does slow down improvements. There are discussions on the Fortran list also with opposite view: that keeping backwards compatibility is killing Fortran adoption. I don’t have a definite opinion on that, but in general I find that it is not realistic to expect anything in computing to last too long.

What Stephan said is that there will be a Julia 2.0 if the changes are worth the breaking cost.

That is work in progress.

4 Likes

Right, but again, these files are not catable and compiled as one unit (which is what we’re talking about when talking about syntax). What gfortran does (as far as I can tell) is determine based on the file extension which format/fortran version the source code is written in, compile that independently to machine code and then link it all together after the fact (at which point, it’s all machine code and there is no more fortran for the compiler to look at). In essence, gfortran contains several different fortran compilers, each for a different version of Fortran. This is a different kind of beast from compiling it all as one unit. It’d be akin to compiling fixed form F77 with gfortran -ffree-form file1.f77, which obviously won’t work.

Sure, julia could do something similar, but that again has nothing to do with whether or not julia introduces breaking or non-backwards compatible changes. It’d mean including the old julia compiler with the new version and doing some autodetection for which compiler to use internally.

4 Likes

You may be right, but I think this is a reasonable trade-off.

Supporting code from decades ago with the latest version of a language may have been important in the 1970s when most papers required less than a few hundred or thousand LOC which was mostly self-contained.

But when packages are used, things move on anyway so running some code with the original version of the language in a reproducible environment is an acceptable extra cost for most people. Running code from a project written for Julia 1.x will remain possible practically forever, even if it may be a minor hassle in a few decades.

In the meantime, breaking compatibility in minor ways when it matters allows a language to develop.

9 Likes

I don’t think that’s quite right? It seems only the dependencies that were explicitly (or transitively) installed in the project environment are recorded. Dependencies available from another environment higher in the directory tree are not recorded in the local project file.

It might seem like a detail (the missing dependencies are recorded in the parent project file) but I think it’s a significant: if I execute using PackageXXX and it works because it was already in my v1.6 environment, I probably won’t realize, leave it at that, and boom! my project is not reproducible.

(This breaks reproducibility in the sense that the project file and manifest that I would typically send or archive don’t have all the dependencies. But also in the sense that PackageXXX in v1.6 will probably be updated while working on something else, and the information of which version was used in my project will be lost.)

I wish this nested environment feature was opt-in.

1 Like

The manifest file has all of this recorded. If you want to fully reproduce the package manager state, just instantiate a manifest.

5 Likes

That’s not actually such a hard optimization to do, although it wouldn’t be done by literally transforming the code. The same effect can be accomplished, however, if the compiler can prove two things:

  1. x doesn’t escape and so its memory can be reused
  2. x has the same size on each iteration

That allows the compiler to reuse the same memory for x on each iteration. This is semantically a bit different from the version where its the same x reused in each iteration, which only overwrites the contents of x, but since the non-data parts of the new x instances are the same on each iteration, the implementation of the two ends up being identical.

2 Likes

Doesn’t seem so, I just checked on 1.7-beta3, in a local Julia project I can use packages from v1.7 and they are not added to the manifest.

Even if they were, it would not solve the problem: if you put the project on another PC where the v1.7 project file doesn’t list the package, it won’t use the information in the manifest: since no Project.toml knows the package it will prompt to install the latest version (even if you instantiated the project before).

IMHO this discussion is pointless (about how much time a language can last). As my bank says: “previous gains cannot be used as a guarantee of the future earnings”. Fortran can stay with us for a long time, or it can die due to lack of interest. Maybe the Fortran compiler would not be optimized to reach the fastest performance possible in the next generation of processors. On the other hand, Julia can also die before 2.0, or it can be the new Fortran.

If you like Fortran, and it fits your needs, then you are good to go. For me, I just cannot imagine starting any new project using a language like Fortran. The prototyping is so much faster in Julia, that for my problems, it pays off even if the performance is 2x worse (it is not, my implementations of Fortran algorithms in Julia are between 2% to 10% faster). Finally, in my case, it is not about performance, the ecosystem is even more important. In Julia, we have DifferentialEquations.jl, a fantastic work led by @ChrisRackauckas. This ODE solver framework is unmatched for simulating complex control problems, IMHO.

17 Likes

That’s how the load path works: at the top-level (in the REPL or a script), you can load anything in the load path, which defaults to include the local project but also your shared global packages and stdlibs. If you want to limit what can be loaded to only the current project, you can do export JULIA_LOAD_PATH=@. or put push!(empty!(LOAD_PATH), "@.") in your script. Then it will only be possible to load the local project packages at the top-level. This is unnecessary for code that occurs inside of packages — there only explicitly declared dependencies are available by default. It’s often a good idea to factor reproducible code into a package and run it by invoking a main() or start() entry point.

5 Likes