My profile picture, an random AI generated image. A circular building with white walls and magnificent skylight, through which a bright blue sky with fluffy clouds scattered throughout is visible. uncenter

Learning Fortran

·

While I probably should be learning a language like C, Go, or whatever new trendy language the ThePrimeagen mentions on Twitter (OCaml?), I'm going to attempt to learn Fortran[1].

A quick history

Fortran, which stands for FORmula TRANslator[2], was created at IBM by John Backus in 1957 for scientific applications and has apparently been popular for high-performance computing and benchmarking supercomputers in recent years. Fortran has had several subsequent releases since then; FORTRAN 77, Fortran 90, Fortran 95, Fortran 2003, Fortran 2008, and the latest Fortran 2018.

Which version of Fortran?

To understand what version of Fortran to learn/use, we first must understand the difference between fixed form and free form Fortran. The fixed form layout comes from the very beginning of Fortran, inherited from punch cards, and has odd restrictions about the column in which comments and statements are placed. The free form layout, first introduced in Fortran 90, removed special columns and added the ability to write comments wherever, and is what we'll be learning in this article. The compiler we'll be using is GNU Fortran, or gfortran. You can install it via Homebrew (macOS) with the gcc formula, or install it using a package manager for your OS. To tell gfortran that your code uses the free form layout, set the file extension to .f90 or newer. The following comment on the Fortran discussion board explains this well.

The .f90 suffix means that the source code is free format, not that
the code conforms to the Fortran 90 standard. Code that uses the .f90
suffix can use features from any Fortran standard. All Fortran
compilers recognize .f90 as a suffix indicating free source form, but
some may not recognize a suffix such as .f95, .f03, .f08, or .f18.
Some users may have build tools that do not recognize suffixes other
than .f90. Most Fortran source code on GitHub that uses features from
a standard more recent than Fortran 90 still uses the .f90 suffix.

Understanding the syntax

Coming from TypeScript, and before that, Python, I'm very used to (and comfortable with) modern — you might say "aesthetic" — syntax . Although I wouldn't say Fortran syntax is quite modern, it seems to avoid the syntactic sugar nightmares that plague beginners in other languages[3]. Take a look at this helloworld.f90 example below.

program helloworld

  print *, 'Hello, world!'

end program helloworld

Older Fortran programs required the use of SCREAMING_CASE for all keywords, but in modern Fortran you can and it is recommended to use snake_case (you can still use SCREAMING_CASE or any other case you want though).

Just from this small example we can gather that...

The syntax for printing is a little funky though. What is that asterisk doing there? The asterisk, aside from being used as a mathematical operator, indicates the "default". So for print, * means "print to the default output channel" (or "print to the default output file unit" to be precise), which is typically going to be STDOUT.

I can't find exactly where this is documented but you don't actually need the start and end program <program-name>; you could write a hello world program like this, though as I just mentioned this doesn't seem to be a common practice and isn't really very useful in any practical scenario.

print *, 'Hello, world!'; end

Here's another, slightly more complicated example.

program calculator
  implicit none

  real :: x, y, answer
  character(1) :: choice

  print *, 'x:'
  read *, x
  print *, 'y:'
  read *, y

  print *, '+, -, *, /:'
  read *, choice
  if (choice == '+') then
    answer = x + y
  end if
  if (choice == '-') then
    answer = x - y
  end if
  if (choice == '*') then
    answer = x * y
  end if
  if (choice == '/') then
    answer = x / y
  end if

  print *, 'Answer:', answer

end program calculator

Starting right at the top, we have something new: implicit none. Added in Fortran 90, implicit none disables implicit typing defaults and all variables must be explicitly declared. In Fortran, implicit typing is the practice of assigning default types to variables based on the character a variable name begins with. Variables starting with I through N are INTEGERs, everything else is REAL. It is "a legacy of the past" and usage of an implicit none statement is "strongly advised" (implicit none - Fortran Wiki).

A common Fortran joke goes along the lines of “GOD is REAL, unless declared INTEGER"[4] because of implicit typing!

Moving on, we declare our first variables in this program.

real :: x, y, answer
character(1) :: choice

Here we are declaring x, y, and answer with the REAL type, and choice with the CHARACTER type. The REAL type stores floating point numbers[5], and CHARACTER... stores characters.

Next, we prompt the user for our x and y values.

print *, 'x:'
read *, x
print *, 'y:'
read *, y

Notice how we can take input from the user with read and assign it to a value with the read *, <variable> syntax. The asterisk here means read from the default input channel/file unit, which would be STDIN.

We do the same for prompting the user to select an operation.

print *, '+, -, *, /:'
read *, choice

Finally, we use a series of basic if-statements to calculate our answer and display it in the terminal.

if (choice == '+') then
  answer = x + y
end if
if (choice == '-') then
  answer = x - y
end if
if (choice == '*') then
  answer = x * y
end if
if (choice == '/') then
  answer = x / y
end if

print *, 'Answer:', answer

If we run this, we- wait. Did I even tell you how to compile a Fortran program yet?

How do I actually run this?

First, compile our calculator program with gfortran -o calculator calculator.f90 . Then you can run it with ./calculator. If you only instruct gfortran of the input file (gfortran calculator.f90), the default output executable will be named a.out.

Let's run our program now.

$ gfortran -o calculator calculator.f90
$ ./calculator
 x:
10
 y:
2
 +, -, *, /:
*
 Answer:   20.0000000

Pretty cool, huh?

A few improvements

Our calculator isn't perfect yet though. What if the user tries to divide by zero?

 x:
10
 y:
0
 +, -, *, /:
/
 Answer:         Infinity

Probably not the answer you expected. Let's try to fix that.

if (choice == '/') then
  if (y /= 0.0) then
    answer = x / y
  else
    print *, 'Error: Division by zero is not allowed.'
	stop
  end if
end if

Here we use the inequality operator, /=, to check if the y value is zero. Now, if the user tries to divide by zero, we'll print an error message and use the stop statement to end the program.

Great. We got rid of the zero division mess, but our code isn't pretty at all. Who wants a bunch of if statements? We can simplify this using the select case statement (also known as the case statement).

select case (choice)
  case ('+')
    answer = x + y
  case ('-')
    answer = x - y
  case ('*')
    answer = x * y
  case ('/')
    if (y /= 0.0) then
      answer = x / y
    else
      print *, 'Error: Division by zero is not allowed.'
      stop
    end if
  case default
    print *, 'Invalid choice. Please choose +, -, *, or /.'
    stop
end select

This also has the handy benefit of telling the user if they made an invalid choice while selecting the operation.

That’s just a quick introduction to a few modern Fortran features: declaring variables, printing and reading to and from the terminal, if and select case, and stop. Next time, we’ll talk more about where Fortran is actually used, cooler things you can build with it, and how the Fortran language & community are rapidly modernizing!


  1. Ironically, in the ~3-ish months since I started writing this article, ThePrimagen has recently said he "take[s] back everything i said about FORTRAN" — apparently having some interest in the language! ↩︎

  2. According to sources listed on Fortran's Wikipedia, the name might also have stood for Formula Translating System or just Formula Translation. ↩︎

  3. See The Rust programming language absolutely positively sucks : r/rust and Rust is a nightmare to learn coming from Java - community - The Rust Programming Language Forum. ↩︎

  4. The first letter of "GOD", a "G", is not within I through N and is therefore of the REAL type ("GOD is REAL"). ↩︎

  5. You can also use double precision for larger (more precise) floating point numbers. ↩︎

The package that broke NPM (accidentally)