Arbeiten mit Fortran in 2020: Do’s and Don’ts

Ein Knigge für Fortran-Developer

© iStock/doomu & unsplash/@sincerelymedia

14.10.2020

Der Name Fortran setzt sich zusammen aus “FORmel TRANslator”und ist eine der ältesten Programmiersprachen. Für viele Softwareentwickler ist sie der Archetyp für eine alte, behäbige, eingeschränkte und schwer zu verstehende Programmiersprache mit der man am besten nichts zu tun haben möchte. Für die alten Versionen von Fortran mag dieses Vorurteil wirklich wahr sein. Fortran hat sich in seiner langen Geschichte aber viel verändert, sodass in seiner “modernen” Variante (wie etwa Fortran 2003) die Sprache einen viel schlechteren Ruf hat als ihr zusteht. Der typische Use-Case für Fortran als Programmiersprache sind rechenintensive numerische Simulationen, wie etwa Wettervorhersagen, Strömungssimulationen, Stabilitätsberechnungen, uvm.

Aus alt mach neu

Fortran gilt als die erste jemals realisierte höhere Programmiersprache und wurde in den Jahren 1954 – 1957 von IBM entwickelt (FORTRAN I). Der Umfang der Sprache war noch sehr eingeschränkt, zum Beispiel gab es nur Integer (Ganzzahlen) und Reals (Gleitkommazahlen) als Datentypen und noch keine Funktionen. In den folgenden Jahren wurden neue verbesserte und umfangreichere Fortran Versionen entwickelt (FORTRAN II, FORTRAN III, FORTAN 66). Das nächste große Update bekam Fortran im Jahr 1977 (FORTRAN 77). Durch neue Features in der Sprache wurde diese Version sehr populär und damit schnell zu “dem” Fortran. Auch heute noch ist, wenn über Fortran Code gesprochen wird, hauptsächlich FORTRAN 77 Code gemeint, was auch die vielen Vorurteile gegenüber der Sprache erklärt. Seitdem gab es noch einige Updates der Sprache, die sie an moderne Programmierkonzepte und Standards heranführen.

Große Meilensteine in der Entwicklung waren die Updates zu Fortran 90 und Fortran 2003, welche neben der Namensänderung (FORTRAN → Fortran) gängige Konzepte wie unter anderem freie Sourcefile Formate, Module, Operator Overloading, Derived data types, Pointers und objektorientiertes Programmieren zur Programmiersprache hinzufügten. Zusätzlich dazu gab es mit Fortran 95 und Fortran 2008 jeweils ein kleines Update der Sprache. Die aktuellste Version des Fortran Standards ist Fortran 2018, wobei noch kein Compilerhersteller alle Features unterstützt.

Do’s & Don’ts in Fortran

Durch die lange Entwicklungsgeschichte von Fortran und um Kompatibilität mit Legacy Code zu wahren, gibt es zahlreiche veraltete und teils obskure Sprachfeatures in aktuellen Fortran Compilern. Eine umfassende Sammlung von “good and bad codingpractices” würde den Umfang dieses Artikels bei weitem sprengen. Dennoch möchten wir einige gängige Altlasten präsentieren, die sich in Legacy Code wiederfinden können, genauso wie ausgewählte Möglichkeiten, die neue Fortran Standards bieten. Für eine umfangreiche Liste von Do’s and Don’ts verweisen wir auf (1).

Don’t use common block and equivalent statement

In Fortran 77 und früher war es üblich, dass verschiedene Variablen auf dieselbe Speicheradresse verweisen, nämlich mittels dem common block und dem equivalent statement. Diese Ausdrücke wurden genutzt, um Information zwischen Subroutinen zu teilen oder um (teuren) Speicherplatz für temporäre Variablen wiederzuverwenden. Mittlerweile sind diese Ausdrücke als obsolete deklariert und sollten nicht mehr verwendet werden. Um Daten zwischen Programmteilen auszutauschen sollten Module genutzt werden und Speicherplatz sollte bei Bedarf dynamisch allokiert und deallokiert werden.

Avoid using GOTO

Kein anderer Ausdruck ist so sehr mit Fortran verwurzelt wie das GOTO. In alten Programmen findest sich sehr oft eine exzessive Nutzung von GOTOs, teilweise auch geschuldet dem Mangel an alternativen Konstrukten. Über die Zeit haben sich verschiedene Varianten des GOTOs entwickelt, wie dem computed GOTO statement oder dem assigned GOTO statement. Auch gab es für die Handhabung von Schleifen oder IF-statements Varianten, die mit Sprüngen zu entsprechenden Labels arbeiten. In modernen Fortran Programmcodes sollten all diese Varianten der GOTOs wenn möglich vermieden werden und durch IF und SELECT Case (= switch) ersetzt werden. Eine nennenswerte Ausnahme für die Notwendigkeit von GOTOs in Fortran Code ist das Fehlermanagement, da Exceptions in Fortran nicht existieren.

Avoid SAVE attributes

Das SAVE Attribut erlaubt es, dass Variablen bei wiederholten Funktionsaufrufen ihren Wert beibehalten und gerade in Verbindung mit Parallelisierung kann dies zu schwer zu findenden Bugs und Dataraces führen. Das SAVE Attribut kann gefahrlos bei Variablen verwendet werden, die immer denselben Wert bei jedem Funktionsaufruf besitzen, um so etwas Performance zu gewinnen. In allen anderen Fällen sollte es gemieden werden. Eine besonders hinterhältiges “Feature” von Fortran ist es, dass alle Variablen, die bei ihrer Deklaration gleich initialisiert werden, automatisch ein implizites SAVE Attribut erhalten.

Use implicit none

Ein Konzept aus alten Fortran Standards war, dass undeklarierte Variablen automatisch als REAL deklariert werden, außer jene die mit dem Buchstaben i, j, k, l, m oder n beginnen werden als INTEGER deklariert. Dieses Konzept ist sehr fehleranfällig, vor allem deshalb, weil der Compiler keine Fehlermeldung ausgibt wenn nicht deklarierte Variablen verwendet werden, z.B. durch einen Tippfehler. Durch dieses Konzept hat sich folgender Witz über Fortran eingebürgert: Fortran einzige Sprache wo gilt “God is Real”. Diese automatische Variablendeklaration kann mithilfe von dem IMPLICIT NONE für den aktuellen Bereich deaktiviert werden und es ist “good practice” diese im ganzen Programmcode umzusetzen.

Make use of derived data types and classes

Mit Fortran 90 wurde begonnen die Sprache Richtung objekt-orientierter Programmierung weiter zu entwickeln. Mit diesem Standard wurden user-defined datatypes eingefügt, die es erstmals erlaubten wiederverwendbare Strukturen von logisch zusammengehörenden Daten zu verwenden. Ebenso wurde das Konzept von generics hinzugefügt, sodass derselbe Funktionsname mit verschiedenen Typen verwendet werden kann (es muss aber trotzdem die Funktion für jeden Typ programmiert werden). Gerade mit dem Fortran 2003 Standard wurde nochmal das objektorientierte Programmieren forciert. Spätestens seit dessen sollte versucht werden, Daten und Logik in sinnvolle Klassen zu kapseln und Programmteile über wohldefinierte Interfaces interagieren zu lassen.

Use the module system

Fortran 90 leitete auch eine neue Form einer Programmorganisation ein, nämlich das Modulesystem. Ein Module besteht aus einer Menge von Deklarationen von Daten und Funktionen und Funktionsschnittstellen, die dann in andere Programmteile verwendet und sichtbar gemacht werden können. Zusätzlich bieten Module die Möglichkeit den Zugriff der beinhalteten Funktionen/Daten mittel PRIVATE/PUBLIC einzuschränken. Seit dem Fortran 2008 Standard gibt es sogenannte submodules, die es nun dem Programmierer ermöglichen den Programmcode in ein separates Submodule auszulagern. Die Notwendigkeit für diese ist einerseits, sehr große und unübersichtliche Module zu vermeiden, die Schnittstelle des Moduls klar ersichtlich zu haben, als auch die Recompilationszeiten zu reduzieren.

Don’t rely on short-circuit evaluation

Sehr viele Programmiersprachen evaluieren bei einer logischen Kombination von zwei Ausdrücken nur den Ersten, wenn durch diesen das Ergebnis bereits feststeht. Diese Verfahren wird als short-circuit evaluation bezeichnet. In Fortran ist es aber dem Compiler überlassen, ob short-circuit evaluation verwendet wird, d.h. im Fortran Standard ist es nicht verboten und auch nicht vorgeschrieben. Ein typischer Anwendungsfall für die Notwendigkeit von short-circuit evaluation wäre die Abfrage:

IF (PRESENT(x) .AND. x >0) THEN
     do something with x
END IF

In Fortran gibt es die Möglichkeit von optionalen Argumenten, d.h Parameter einer Funktion, die nicht zwingend übergeben werden müssen. Mit Hilfe der Funktion PRESENT(x) kann überprüft werden, ob der Parameter x übergeben wurde. In dem Beispiel wird nach der Überprüfung eine Abfrage getätigt, ob x größer als 0 ist. Falls x nicht übergeben wird, dann würde durch short-circuit evaluation die Abfrage x>0 nicht mehr getätigt werden, da bereits die erste Bedingung nicht gültig ist. Durch die möglicherweise nicht erfolge short-circuit evaluation würde das Programm an dieser Stelle aber abstürzen. Die korrekte Schreibweise ist das Aufteilen auf zwei einzelne Bedingungen:

IF (PRESENT(x)) THEN
    IF(x >0) THEN
        do something with x
    END IF
END IF

Andere typische Fälle sind Abfragen ob ein Pointer einer Speicheradresse zugeordnet ist oder ob eine mathematische Operation mit den Eingabewerten erlaubt ist (Division, Wurzel, …).

Hier finden Sie weiterführende Informationen.

Quelle: (1) S. Chapman, Fortran for scientists & engineers, McGraw-Hill Education, 4. Edition, 2017

Autor: DI Dr. Christoph Hofer ist Professional Software Engineer in der Unit Industrial Software Applications der RISC Software GmbH.

Kontakt

RISC Software GmbH
Softwarepark 35
4232 Hagenberg
www.risc-software.at