Fortran is easy to learn
craftofcoding.wordpress.com
craftofcoding.wordpress.com
https://en.wikipedia.org/wiki/Magnetic-core_memory
Ancient LISP and BASIC variants also stand out in this regard of not requiring you to undergo years of training and theory to implement and fully understand.Fabrice Bellard's minimalist but complete quickjs.c Javascript interpreter is presently about 54,000 lines of C:
https://github.com/bellard/quickjs/blob/master/quickjs.c
Javascript is an enormous, complicated, designed-by-committee language, as are essentially all other languages we are forced to use. I do hope there is a renaissance of simpler technology, technology not driven by competitive egos but by a desire for the joy of simplicity and understanding. But such simpler technology won't be useful for building backend infra for Big AdTech ad-bidding exchanges so that we can be bombarded with ads for One Weird Trick to burn belly fat or whatever.The original FORTRAN '57 did not even have SUBROUTINE, FUNCTION, CALL, etc., for implementing subroutines. Those came with FORTRAN II in 1958, which was the main language Kemeny's original BASIC was based on in the early 1960s, but Kemeny changed FORTRAN II's DO loop to the easier to remember 'FOR I = 1 TO 42 ...'.
Knuth designed his original 1960s MIX computer using just pencil and paper, designed it to be easy to run programs using just pencil and paper.
If you yourself could not build a rudimentary BASIC or cut-down FORTRAN using only the resources in your brain and a sheet of paper with a pencil, you might be spending too much time working with overcomplicated programming tools that do not bring joy to your life.
If you write a recursive descent parser, you're probably parsing a language that was explicitly designed to be parsed with straightforward code, and that can mean the language is compromising on brevity and expressivity sometimes.
FWIW, I've been using Fortran since the mid 1980s, C from the mid 90s, Python from the mid 00s, and Julia since 2012 or so. All of these languages are fine for the example provided, and all are understandable. Each of these languages require some minimal boilerplate around the core algorithm to make it work. Specifics of input and output mechanisms would be language/dialect specific.
Really, each of them is fine for this trivial example. Its when you start getting into serious translation of the underlying math into something the language will understand, that the real difference stand out.
That's when both Fortran and Julia stand out. Both are designed to make this process as painless as possible. Fortran was designed and built almost 70 years ago. IO was very painful then, and while the language itself is very simple and easy to understand, the IO system is still quite similar to the early days.
The "(,)" notation combines units (file descriptors), and formatting. It is not different in intent than the scanf and other functions.
Why Fortran and Julia are so easy to use comes from the expressiveness of the language, the simple mechanism of writing code that looks close to the formulae in question. There is no fiddling with array indexing that doesn't start where the formula indicates. No allocating arrays of arrays to build matrices.
That is, it is simple to go from conception to working code very quickly. In a manner that really does look like the way you would do it on paper.
That's why Fortran is still in use, and growing. And why Julia is catching on quickly.
Why would it not in any other languages?
I am not saying it makes other languages unusable (I use numpy arrays quite frequently; Python and Fortran are very complementary), but definitely less natural and elegant.
1. The matrix multiplication syntax used to be bad. But it became possible at some point to write A @ B for the product of A with B. And that seems fine to me.
2. The code seems more natural when you write `sin(array([1,2,3]))` instead of `np.sin(np.array([1,2,3]))` -- which you can achieve by running `from numpy import *`, but doing this is discouraged by a lot of people.
3. The convention in Linear Algebra is that indexing starts from 1, not 0. This sometimes makes translating from a language which follows the more usual convention difficult.
Overall though, I think only 3 is unfixable, but this is usually a minor problem. Usually, Python+Numpy doesn't seem any worse than Matlab syntax-wise.I find the experience of using Pandas to be much worse. Sympy also feels abrasive because of needing to write `m12 = var('v12')`.
Although I agree that some languages like Julia and say MATLAB feel more fluent to express mathematics.
It's like driving on the left side of the road instead of the right side of the road. Inconsistency is what makes it painful.
One should not need to adjust the way one expresses an algorithm, because of opinionated language design decisions. Put another way, languages designed for scientific/engineering computing won't have a hard/fixed opinion about things that shouldn't be worried about.
By the way, your point about polynomials works in favour of the convention that 0 is a natural number.
(Besides, there's uncountably many things you have zero of in you room.)
So one isn't a natural number?
> (Besides, there's uncountably many things you have zero of in you room.)
;) Exactly. Zero is the most natural number.
You can even do arbitrary indexing: fixed like A(-3:3) or dynamically like B(n1:n2). This may sounds useless but it's actually an excellent feature when writing eg convolution kernels.
I don't know of any other languages beyond Fortran and Julia that have arbitrary array indexing as a core feature (you can fake it in C in two lines I guess).
It is small but really makes things more elegant. I should definitely try Julia. I've spent a lot of time calculating awkward array index conversion formulae in my head and this could make things a lot more simple especially for weird cases.
I was under the impression that Fortran's only redeeming benefit was that it compiled well for numeric computing routines.
So let's break that down.
The base standard library and "idiomatic" Julia are both largely written without the assumption of 1-based indexing, instead dispatching to what you think about as an array-oriented dsl, which is this interface: https://docs.julialang.org/en/v1/manual/interfaces/#man-inte...
It is very normal in Julia to implement such interfaces to do what you want. Julia uses these types of internal interfaces with multimethods in lieu of a lot of compiler intrinsics.
So I would say Julia and Fortran have different implementations of arbitrary indexing.
They are both oriented around core design features of each respective language.
One can see it in the implementation of `filter!` for example https://github.com/JuliaLang/julia/blob/ab4e036b9209967b4273... :
Julia's arrays system is built so that most arrays that are used are not the simple Base.Array. Instead Julia has an AbstractArray interface definition (https://docs.julialang.org/en/v1/manual/interfaces/#man-inte...) which the Base.Array conforms to, and many effectively standard library packages like StaticArrays.jl, OffsetArrays.jl, etc. conform to, and thus they can be used in any other Julia package, like the differential equation solvers, solving nonlinear systems, optimization libraries, etc. There is a higher chance that packages depend on these packages then that they do not. They are only not part of the Julia distribution because the core idea is to move everything possible out to packages. There's not only a plan to make SuiteSparse and sparse matrix support be a package in 2.0, but also ideas about making the rest of linear algebra and arrays themselves into packages where Julia just defines memory buffer intrinsic (with likely the Arrays.jl package still shipped with the default image). At that point, are arrays not built into the language? I can understand using such a narrow definition for systems like Fortran or C where the standard library is essentially a fixed concept, but that just does not make sense with Julia. It's inherently fuzzy.
The fortran version is super neat, especially in conjunction with stack allocated multidimensional variable length arrays.
Recall that FORTRAN stands for FORmula TRANslator.
FORTRAN is built for math. It makes math expressions — particularly, linear algebra stuff — easy to write, and running very, very fast. There are much better tools for text processing (there's perl, python, pandas, and everything in between). But for raw math, there's Fortran.
That's why everything is still powered by Fortran.
Yes, from Matlab to your fancy neural network, numpy, scipi, scikit-learn, etc., the actual computational core - BLAS/LAPACK is Fortran-based.
That's why Matlab feels like Fortran. And that's why numpy semantics are different from python's: because it is heavily inspired by Matlab, and, like Matlab, wraps FORTRAN code in a friendly manner.
But in the end, it's FORTRAN all the way down. Even in Julia.
(And that's how I ended up fixing a minor bug in Google's FORTRAN sparse svd package, PROPACK[1], in 2019. Well, PROPACK was written before Google existed, but they have hired the author for a reason. The bug was only in the way an error message displeased the internal memory leak checker; in other words, FORTRAN text I/O was an issue. Stay away from that, and it's the best tool for the job.)
Unless you're using [Octavian.jl](https://github.com/JuliaLinearAlgebra/Octavian.jl) or such for your linear algebra in place of BLAS. But yes, it is always interesting how many people do not know how much of modern software is built on Fortran!
And for many people, it isn't/hasn't been/doesn't have to be.
That's the author's take as well:
>The idea of introductory languages is not necessarily that they are suited to commercial endeavours, but rather that they are (i) easy to implement algorithm in, (ii) readable, and (iii) do not contain things that will confuse and bewilder.
That's not true. None of the Julia differential equation solver stack is calling into Fortran anymore. We have our own BLAS tools that outperform OpenBLAS and MKL in the instances we use it for (mostly LU-factorization) and those are all written in pure Julia. See https://github.com/YingboMa/RecursiveFactorization.jl, https://github.com/JuliaSIMD/TriangularSolve.jl, and https://github.com/JuliaLinearAlgebra/Octavian.jl. And this is one part of the DiffEq performance story. The performance of this of course is all validated on https://github.com/SciML/SciMLBenchmarks.jl
Does Julia not use OpenBLAS at all now?
I don't see great attraction in "flipping" to MKL. (In general I switch BLASes by dynamic linking if necessary.) I'm puzzled by the value of "rather bad" for OpenBLAS, at least for BLAS [1], but it seemed OK against MKL for LAPACK-based R benchmarks I measured on sandybridge. That said, I don't understand why people avoid AMD's BLAS/LAPACK (BLIS/libflame with enhancements intended for merging) on AMD systems. In this context: BLIS studiously avoids Fortran for some reason, even for test the Fortran interface.
I have nothing against Julia, incidentally; I have the original Dylan book.
1. https://git.sr.ht/~fx/blis/tree/performance/docs/Performance...
> not the default, I've now checked
Whatever the Julia default build is doing, so probably not the recursive LAPACK routines then if that's how it's being built. If there's a better default that's worth an issue.
> That said, I don't understand why people avoid AMD's BLAS/LAPACK
There just isn't a BLIS wrapper into Julia right now, and it's much easier to just write new BLAS tools than to build wrappers IMO. It makes it very easy to customize to nonstandard Julia number types too. But I do think that BLIS is a great project and I would like to see it replace OpenBLAS as the default. There's been some discussion to make it as easy as MKL (https://github.com/JuliaLinearAlgebra/BLIS.jl/issues/3).
OB seems to me a better general default than BLIS, though its threading implementation may not be robust. BLIS is even broken on POWER9, and I don't remember whether the dynamic micro-architecture selection ever added for other than x86.
For really small matrices on x86, I'd front BLAS with libxsmm, but I don't remember where it starts winning, or know the threshold for BLIS' non-packed kernels.
Anyway, thanks for the info. I should be embarrassed never to have made time to look seriously at Julia.
> though its threading implementation may not be robust
That's one of the main issues I have with it. Its poor threading behavior coupled with a bad default (https://github.com/JuliaLang/julia/issues/33409 one of my biggest pet peeve issues right now) really degrades real user performance.
Mainly:
> Certainly things like I/O are still problematic for the novice programmer in these languages.
Poor I/O basically killed my interest in programming in most languages when I was a novice. BASIC was great for this. QuickBasic was, and probably still is king. People new to programming want to do fun stuff, and it's very hard to do without I/O. Me and most of my peers spent a fair amount of their hobby programming writing very simple games, or doing fun graphics stuff (drawing lines, circles, etc).
After doing this for a while in BASIC and QB, "serious" languages like C/C++ were pure Hell. I could literally do none of the cool things I used to with only a rudimentary command of the language. Did not know about Perl/Python until much later.
In my opinion, if you want learning languages to be fun, provide one where:
- Text I/O are no-brainers
- You can easily respond to keypresses (i.e. detecting if a button was pressed and not having to wait till the user hits Enter).
- Rudimentary graphics: Plotting a point, drawing a line and circle. Coloring it as desired.
- Easy way to generate random numbers.
Teach people these things, and they can have a lot of fun with loops, conditionals, and functions.
I do think that if one is an engineering student (not necessarily CS/CompE), then it's more useful to teach how to do useful stuff (e.g. automation) in languages like Python. In my day most schools used either C/C++ or Java - both of which are not very useful for people whose primary job is not coding. Engineering students would take that one course and that's it. However, I suspect most engineers will benefit greatly if they knew Python. Lots of tedious stuff to automate.
Even if the introductory course uses Python, I think they should cover useful tasks for automation - handling directories, and perhaps some basic network related stuff via requests. If you can't squeeze it into one course, make another one and make it mandatory. It'll be more useful than many engineering courses they'll take.
Looking back, I think QBASIC/QuickBasic had it right in contrast to other learning languages. You don't need a DSL, turtle graphics, drag-and-drop code blocks, or any of that stuff to teach programming. Just make the hurdle to getting useful input and output minimal, and the prospective programmer can take it from there.
On the other hand, I do wish I had been able to pick up things like C much earlier in life. Only recently did I actually learn C++ in my 30s, even though part of me wanted to learn it when I was 9. I think that things like QBASIC can also be a sort of trap because if the I/O is so easy then it can be difficult to leave it for something that actually is better but not in an obvious way to a novice.
It was later replaced by DarkBASIC Pro (which was eventually open sourced years later) but that one used a more traditional IDE that was kinda reminiscent of a simplified Visual C++ 2005 and had a more complex language.
[0] https://i.imgur.com/UKZtMue.png
Its origin is really showing: UNIXes and their line-oriented terminals. No notion of a screen-oriented console, let alone a graphical one, unlike most BASICs aimed at personal computers.
It's still poor compared to most languages I've used. String formatting is not simple for beginners. In Python you can do:
print(num_eggs)
where num_eggs is an integer. In C you have to do: printf("%d", num_eggs);
One is much simpler than the other.And on top of that, I detest languages that force you to manually enter newlines by default. Probably over 90% of use cases require a newline, so why not have the function add it by default, and either provide another print function or optional parameter for the times when you don't want a newline? The "I forgot to add a newline" headache is extremely annoying. Whereas in languages that add it by default, I rarely find myself saying "Ouch. I actually didn't want a newline there."
When evaluating what is good for beginners it helps to remember not all beginners approach programming from the same place. Traditionally computational scientists were a distinct and equal in size subset of the users of computer resources in academic and industry research centers accross the nation, specifically distinct from computer scientists. Today they are smaller total fraction but that history continues to inform how they approach computation and mentor new scientists learning to use computers for science, which diverges from the way computer scientists do both in approach and requisite mental model.
The article is about teaching programming in general, not teaching it for computational needs:
> in any respects modern Fortran is an exceptionally good language to teach programming in
> Partially it is because modern Fortran is easy to read and comprehend, which is an important factor for the individual learning to program for the first time.
> The idea of introductory languages is not necessarily that they are suited to commercial endeavours, but rather that they are (i) easy to implement algorithm in, (ii) readable, and (iii) do not contain things that will confuse and bewilder.
You can also see his prior blog posts where again he is speaking about learning programming in general - not limited to computation.
10 INPUT "Height above sea level(m)", H
20 D=SQR(2*6367.45*(h/1000.0)
30 PRINT "Distance to horizon", D
RUNBASIC even had crude array math via the MAT statement though I don't recall the details.
I got to my senior year, second semester, and had a meeting with my advisor to make sure I had met all of my graduation requirements. He looked at my record and said: "Hey, you were supposed to take a programming class. But you know how to program, don't you?" I said yes. He checked the box to waive that requirement for me. Then I started breathing again.
* https://www.manning.com/books/modern-fortran
* https://fpm.fortran-lang.org/en/index.html #include <iostream>
int main(void)
{
float height, dist;
std::cout << "Height above sea level(m): ";
std::cin >> height;
dist = sqrt(2*6367.45*(height/1000.0));
std::cout << "Distance to Horizon " << dist << " km\n";
return 0;
} write (*,*) "hi"
means write to standard output (the first asterisk) using a default format (the second asterisk) chosen by the compiler. I agree it's a bit obscure. An alternative is print*,"hi"
The :: just separates the type of variable from the variable names. The code shown compiles and runs the same if the :: is removed, but there are cases where the :: is needed.I have no idea which year’s flavor of Fortran is shown… are implicit variable types based on what letter the variable starts with still a thing? I notice the “real :: …” in the listing…
I thought it was kind of quaint feature as I started learning “real languages” after that. All these years later, I kinda thinks it’s clever/original now.
> The idea of introductory languages is not necessarily that they are suited to commercial endeavors, but rather that they are (i) easy to implement algorithm in, (ii) readable, and (iii) do not contain things that will confuse and bewilder.
I write Fortran professionally and it is a real pain in the dick to get anything done. It has some nice SIMD and matrix operation syntactic sugar but that is about it.
If you want to get anything useful done you are better off writing in another language.
The Fortran ecosystem is running on fumes from the inertia of these massive legacy code bases that no one wants to pay to rewrite. But then complain that it is expensive to get anything done in them.
For SIMD, Chris Elrod's LoopVectorization.jl [1] is an (IMHO) incredibly impressive piece of work (which incidentally provides the foundation for I think the first pure Julia linear algebra library competitive with BLAS).
Multithreading is pretty easy with things like `@spawn`/`@sync` and `@threads for` in the base language, as well as super low-overhead multithreading from the Polyester.jl [2] package (which LoopVectorization also uses to provide a version its vectorization macro that'll also multithread your loops in addition to SIMD-vectorizing them).
MPI.jl [3] has been totally problem free for me, though I wouldn't be surprised if the Fortran bindings still have an edge somewhere, and Cuda.jl [4] seems to provide pretty seamless GPU support which should play nicely with MPI.jl's Cuda-aware MPI [5], but I don't work as much with GPUs myself.
[1] https://github.com/JuliaSIMD/LoopVectorization.jl
[2] https://github.com/JuliaSIMD/Polyester.jl
[3] https://github.com/JuliaParallel/MPI.jl
[4] https://github.com/JuliaGPU/CUDA.jl
[5] https://juliaparallel.github.io/MPI.jl/latest/usage/#CUDA-aw...
Would it be a good language to use outside of specialized needs? Probably not.
I've also heard rumours of Julia and even Rust being used (the latter because of the ability to reuse libraries in the browser e.g. for visualisation), but the writers of these codebases (and the Fortran/C/C++/Java) are unusual—Python and R (and for some holdouts, IDL) are what are most people write in (even if those languages call something else).
After a certain threshold is very hard to get people to move on when the IT managed compilers just work, and coding isn't a full time activity.
x ** (1/2)
You mean, and one could make a point about that being a non-standard way of raising exponents for a complete noviceWhen discussing teaching C to beginners, no one is insisting on bringing up considerations for the C compilers of 1972 or their dialects. When discussing teaching new speakers of English how to ask someone their name, no one says, "yes, but in old English you'd need to say 'Hwæt hātest þū?'". I can't really come up with a pithy dismissal regarding Euclid, but not to get too metaphysical, the idea that Python 2.7, C, or English - human constructs - are comparable to Euclidean geometry, which is a sort of immutable construct of logic and/or human cognition, is just plain bizarre. Ideas are timeless; software isn't. I don't begrudge us for using Unix per se - it's a damn fine idea after all - but as elegant as it is, there's no good reason to be running V7 these days.
Or, to return to a different OS: again - in the year 2000, Windows 2.1 was 12 years old. Would you have said then, "there's nothing wrong with using Windows 2.1; after all, English is 1000 years old and we still use it?"
Whether 1/2 gives you 0 or 0.5 is not an issue of the implementation; it's an issue of the language semantics.
Software is applied mathematics. It doesn't break down or wear out like an old car. There's nothing wrong with using Windows 2.1 if you like it, but it wasn't very good in the first place, and there are legal problems with copyright law that prevent you from fixing its problems and making it run well on modern hardware.
And so the problems with using Windows 2.1 are precisely the same as those with using Python 2.7 - you miss out on ever-mounting additional features that make your life easier; you miss out on an ecosystem which is no longer compatible with it; you miss out on security or bug fixes and need to deal with those issues yourself; you miss out on newer, faster, more reliable or efficient or even just existent hardware (could I find a printer for a Windows 2.1 box if I wanted to?); if you're working with other people, you'll find them harder to find and need to train more and more of them as they're increasingly unfamiliar with the dated system.
And all of these effects stack - you don't just lose out on upgrades for Python, you lose out on new features or bug fixes or security updates for the libraries you use that have stopped supporting Python 2.7 too, and so on. Your world gets smaller and smaller as the rest of the world gets bigger and bigger.
If you're maintaining a legacy system, and you don't want to risk changing it in any way unless absolutely necessary, because you're a bank or controlling medical or nuclear equipment or something, then that's something to weigh. But in any case, by refusing to upgrade when the rest of the world has moved on, you're racking up a technical debt that will grow by the day.
On the other hand, the performance + high level nature of Julia makes it a rather excellent tool for this. In the MIT graduate course 18.337 Parallel Computing and Scientific Machine Learning (https://github.com/mitmath/18337) we do precisely that, starting with direct optimization of loops, then moving to linear algebra, ODE solving, and implementing automatic differentiation. I don't think anyone would want to give a homework assignment to implement AD in Fortran, but in Julia you can do that as something shortly after looking at loop performance and SIMD, and that's really something special. Steven Johnson's 18.335 graduate course in Numerical Analysis (https://github.com/mitmath/18335) showcases some similar niceties. I really like this demonstration where it starts from scratch with the 3 loops and shows how SIMD and cache-oblivious algorithms build towards BLAS performance, and why most users should ultimately not be writing such loops (https://nbviewer.org/github/mitmath/18335/blob/master/notes/...) and should instead use the built-in `mul!` in most scenarios. Students should leave the course knowing generally how BLAS is implemented but also how to use it most effectively. There's very few languages where such "start to finish" demonstrations can really be showcased in a nice clear fashion.
It was fairly easy to learn the language and port the C/Perl/TCL CGI things I normally did. In fact, I ended up writing library much like Don Libes cgi.tcl that was somewhat popular back then.
Surprisingly one of my favorite data projects (https://retrosheet.org) has tools that will output data in a format that makes it really easy to read in FORTRAN. So, I still use it quite a bit to do some heavy lifting with my baseball research.
height_str=Base.prompt("Height above sea level(m): ")
height =Parse(Float64, height_str)As someone else mentioned, I have been thinking of getting back into FORTRAN.
(setq r 6367.45
h (/ 42.0 1000))
(sqrt (* 2 r h))
23.12716584452146That Python example in there :)
perl -e 'print(sqrt(<>*12.7349))'