What are your favorite and least favorite things about Fortran?

@han190, thank you! I am looking forward for FortranCon also. See you there!

It’s unlikely that any of us will “see” the others at FortranCon, except on a screen. Switzerland is still closed to most non-citizens and won’t even allow other EU folk from entering until 6 July. Those of us from the US are banned. It’s too bad, as I was looking forward to meeting many of you. Maybe there will be another next year.

I will still be doing my keynote.

1 Like

Favorites:
1. Arrays as first class citizens. Array slices, elemental operations, where construct, automatic allocation of arrays, etc. Also 1-based idexing.
2. Syntax is very easy to learn. Looks like pseudocode, no noise with curly braces, semicolons, etc. Doesn’t allow dangerous practices like using asignment results inside expressions, doesn’t allow prefix and postfix increment operators and it’s subtle differences.
3. Target attribute, strong typing, argument intent and interfaces allow for very reliable error checking by the compiler. It depends on the compiler of course, but in my experience error diagnostics are more helpful with fortran than other languages I have used.

Not a fan of:
1. Lack of true generics and containers. Iteration over containers.
2. Does not concern the standard , but the lack of an interpreter or REPL like Python/Java/C++ holds the adoption of the language for many potential users. Things like plots could handled much easier with “magic commands” in something like Jupyter for quickly exploring some problem.
3. Minor annoyance: associate construct binds a name to the value of an expression instead of keeping its state dynamic.

3 Likes

Hi @Pompito, thanks and welcome!

Regarding our Con 2.:, I am working very hard on https://lfortran.org/ to try to fix precisely that problem.

OK, here is my take on modern (2003 and beyond Fortran) as someone who had previous experience with C/C++ and Python.

Four favorites (three was too little for me):

  1. Its object-oriented features are good enough to allow you to create a well-designed, modular code.

  2. With clever choice of variable names, the code can be as readable as an essay. (No: {, }, //, &, *, ->, and what have you in other languages which always make your code look cryptic.)

  3. Because it’s less rich than some other OO languages, it leaves more of your brain capacity free to focus on the physical phenomena you want to model, rather than diverting your attention towards the plethora of architectural possibilities C++ has in its arsenal.

  4. Counting from one (and not from zero) also helps to keep the focus on what you really want to solve. If every time you deal with an array your mind has to go through: OK, I have N members, but they are counted from zero, meaning that the last one is at N-1 it is being constantly distracted.

Least favorites:

  1. String (character) manipulation leaves a lot to be wished for. I am never quite sure what is in a string, where does it start, where will it end, are the blanks included. Maybe I still have to get used to it, but Fortran strings are a twilight zone for me.

  2. Case insensitivity. Being case insensitive, I find it much harder to enforce coding standards among my team members. I know it is needed for backward compatibility , but I really don’t like it.

  3. No argument checking for procedures outside of modules. Like the previous one, I believe it is a feature ensuring backward compatibility, but it always leaves me with a splinter of doubt in my mind if I sent the right arguments or not?

4 Likes

I also don’t fancy the % in OO Fortran a lot, but I thought it was introduced because the dot was already taken by: .ne., .eq., .not. and other logical and comparison operators.

I agree that a programmer should not use foo and Foo in the same procedure. The standard cannot be changed, since too much code would break, but it would be nice if compilers had options to warn about inconsistent capitalization of variables and procedure names. Users could turn those warnings into errors if desired. The g77 manual discussion of case sensitivity is amusing:

9.5 Case Sensitivity

GNU Fortran offers the programmer way too much flexibility in deciding how source files are to be treated vis-a-vis uppercase and lowercase characters. There are 66 useful settings that affect case sensitivity, plus 10 settings that are nearly useless, with the remaining 116 settings being either redundant or useless.

3 Likes

Can you please elaborate on this a little bit further? As you may know, outside of MODULEs, the standard envisions coders using the INTERFACE block. Thus if one has some library code where the MODULEs have not been furnished to the client (as is the case with a lot of “legacy” libraries) but the interfaces are either documented some place or if they need to be “guessed”, the client side of the code can do so one time in INTERFACE blocks and have the rest of the code consuming such libraries be at least consistent with such interface(s). Do you find any gaps in this?

Well, to the best of my knowledge, there is no argument checking in Fortran for procedures outside of modules. There are interface blocks all right, but I see two issues with them: they make the sources longer and if you use them, whenever you change arguments received by a procedure, you should change two files: the procedure itself, and the file in which its interface is defined. I avoid interfaces all together and am doing my best to have as much functionality as I can inside modules.

Agree MODULEs and SUBMODULEs are the way to manage the procedure interfaces consistently with implementations. But when that isn’t possible like with unchangeable legacy libraries and/or 3rd-party providers, the INTERFACE blocks provide the best possible alternative.

I, for one, am glad Fortran introduced MODULEs and SUBMODULEs in its standard revisions when they did, sooner would have been better but better late than never!

1 Like

Intel Fortran, now free for Windows and Linux, has options to check arguments, so ifort -nologo -gen-interfaces -warn:interfaces abc.f90 xabc.f90 for files

function twice(x) result(y)
real, intent(in) :: x
real             :: y
y = 2*x
end function twice
program main
print*,twice(1.0d0)
end program main

gives

xabc.f90(2): error #6633: The type of the actual argument differs from the type of the dummy argument.   [1.0D0]
print*,twice(1.0d0)
-------------^
compilation aborted for xabc.f90 (code 1)
1 Like

I’ll throw in my six cents.

Favourite things:

  1. Reliability. A strong type system and extensive compile-time and runtime checks mean I can rely on my code to give me the correct answer, or to fail really noisily if something goes wrong.
  2. Speed. Things are fast by default, and optimisation is really easy. The nuts and bolts are all exposed, so you can tune them up as much as you like. Libraries like BLAS/LAPACK, FFTW and OpenMP are also great for this.
  3. Interoperability. I can trick any outside observer into thinking my Fortran library is a C library, and basically everything can read a C library.

Least favourite things:

  1. Small ecosystem. It’s really hard to write tools that make other Fortran devs’ lives easier, and so there aren’t many of these tools around, and those that exist are usually the result of spectacular efforts by far-too-small development teams. I’m thinking of things like unit testing, documentation generation, containers, conversion to/from structured files, IDE support and the like.
  2. Slow rate of improvement. Sure, a lot of new ideas in coding are just hype, but some of them are great, and save a lot of dev hours. And Fortran takes absolutely forever to include new features.
  3. Readability. Fortran is extremely, often needlessly, verbose. And there’s no widely used style guide, so every Fortran code is formatted differently, and has different conventions for how everything is done. This makes reading and maintaining code that much harder than it should be.
2 Likes

This is the implicit vs explicit interface. You can make interfaces to external subprograms explicit by specifying an interface body. Some compilers have a tool that will auto-generate a module with the interface blocks of the external subprograms in a bunch of source files (e.g. nagfor =interface *.f90 will create an interfaces.f90 file definining an INTERFACES module which you then USE to make interfaces explicit).

Our polisher, declaration standardiser and python-based style-checker has been a godsend. All our sources look like they have been written by the same person.

2 Likes

Could you give some examples? I agree that a declaration one may write in Fortran,

real(kind=real64), allocatable, intent(out), target :: x(:,:)

is long, but one could argue that such detailed declarations are informative to the reader of the code. In Python you might write an equivalent comment that is not checked by the interpreter. Another case of verbosity is that I start most modules with boilerplate such as

module foo_mod
use kind_mod, only: dp
implicit none
private
public :: f1,f2
contains

but the sections of Fortran code containing executable statements are concise, especially if one is mostly performing array operations.

2 Likes

Sure. A few examples:

  • In procedure declarations, the argument names are duplicated, and a bunch of extra words are needed. Compare the C++
int add(int a, int b){
  return a+b;
}

to the equivalent Fortran

function foo(a,b) result(c)
  integer, intent(in) :: a
  integer, intent(in) :: b
  integer :: c
  c = a+b
end function
  • Fortran is case-insensitive, requires you to declare and initialise variables separately, and doesn’t allow chaining of member functions. Compare the C++
Foo foo(a,b,c)
Baz baz = foo.bar().baz()

to the equivalent Fortran

type(FooType) :: foo
type(BarType) :: bar
type(BazType) :: baz
foo = FooType(a,b,c)
bar = foo%bar()
baz = bar%baz()
  • Fortran has no ++ += etc. operators, so these expressions are twice as long as they need to be.
  • Everything to do with strings in Fortran.

There are just lots of areas where Fortran is more verbose than it needs to be, and where bits of code that are conceptually related are forced apart from one another.

2 Likes

I won’t pretend that Fortran is not verbose, but we could also write:

integer function foo(a,b)
  integer, intent(in) :: a, b
  foo = a+b
end function

And the intent(in) is bringing useful information, both for the reader and the compiler.

3 Likes

Considering a not-too uncommon situation with C++ where a scientist / engineer needing to work with “addable” type foo_t that was initially passed by value and found to be a drag or inadequate, later as a pointer reference and found to be dangerous, and eventually as reference, the following and its history

foo_t add(const foo_t a&, const foo_t b&) {
    return a + b;
}

may look far more distracting relative to what would be the author’s primary focus i.e., her domain expertise in scientific and engineering disciplines when compared to this

type(foo_t) function add(a, b)
    type(foo_t), intent(in) :: a, b
    add = a + b
end function
4 Likes

Yes, and the function, if prefaced with a single word, ELEMENTAL, works not just for scalars but for arrays of the same shape and for combinations of arrays and scalars.

3 Likes

Favourites:

  • Coarrays. Probably my favourite feature of any language.
  • Static, strong typing
  • Array statements and elemental procedures.
  • Reasonably painless interoperability with C via the iso_c_binding.

Least favourites:

  • The % sign. So, so bad.
  • The open source compiler ecosystem is limited.
  • I wish I could just use the C preprocessor, without the quirks of “traditional mode”. I’d rather have this than actual templates, even.
7 Likes