[an error occurred while processing this directive]

Lektion zur Relevanz von Spezifikationen (Normen) für formale Sprachen. [] (abstrakte formale Sprachen (Norm, Spezifikation, abstrakte Programmiersprache, abstrakte Programmiersprachen)), Artikel, Seite 721269
https://www.purl.org/stefan_ram/pub/formal_abstrakt_de ist die kanonische URI dieser Seite.
Stefan Ram

Abstrakte Sprachen

The fact that the program works has no relevance. 

Bartosz Milewski

Bestimmte formale Sprachen, wie etwa C  oder C++, sind abstrakt  definiert.

Diese formalen Sprachen sind nicht durch das Verhalten eines speziellen Verarbeitungsprogramms (einer Implementation) eines speziellen Herstellers in einer bestimmten Umgebung bestimmt, sondern durch eine herstellerübergreifende Norm, also eine in den relevanten Kreisen als maßgeblich akzeptierte Festlegung (Spezifikation) der Syntax (Formulierung) und der Semantik (Bedeutung) von Texten der formalen Sprache.

Abstraktion

Nicht immer ist es sinnvoll, in solch einer Norm alle Details einer Implementation festzulegen. So kann sich der Wertebereich des Datentyps "int" durchaus von einer Implementation zur anderen unterscheiden und doch weiterhin der Norm entsprechen. Es gibt einige Gründe dafür, nicht alle Details einer Sprache zu definieren.

Das Weglassen  der Festlegung solcher Details (wie des genauen Wertebereiches des Datentyps "int") ist ein Akt der Abstraktion. Eine formale Sprache, die unter Zuhilfenahme solcher Abstraktionen definiert ist, kann man auch als eine abstrakt definierte  oder eine abstrakte  formale Sprache bezeichnen.

Abstrakte Festlegung eines Wertebereiches

Im Falle des Datentyps "int" verlangt die Norm "ISO/IEC 9899:1999 (E)" (C99) zur Programmiersprache C  beispielsweise nur, daß eine Implementation mindestens den Wertebereich von −32767 bis +32767 unterstützt. Das bedeutet, daß eine Implementation mit einem int-Wertebereich von −2147483647 bis +2147483647 insofern der Norm voll entspricht, aber auch eine Implementation mit einem int-Wertebereich von −32767 bis +32767 entspricht der Norm insofern vollkommen, während eine Implementation mit einem int-Wertebereich von 0 bis +32767 beispielsweise nicht normgerecht ist.

Portabilitätsfehler

Ein häufiger Anfängerfehler ist es, sich beim Programmieren nach den Eigenschaften einer speziellen Implementation  zu richten. Beispielsweise könnte ein Programmierer mit einem C -Compiler arbeiten, bei dem der int-Wertebereich von −2147483647 bis +2147483647 reicht. Die Funktionsfähigkeit seines Programmes könnte nun davon abhängen, daß der Wertebereich umfangreicher ist als der garantierte Wertebereich von −32767 bis +32767. Der Anfänger wäre zufrieden mit sich und seinem Programm: Denn es „funktioniert“ ja.

Was der Anfänger aber nicht merkt ist, daß sein Programm unter einer anderen Umgebung nicht mehr funktionieren würde, weil diese in vollkommener Übereinstimmung mit der relevanten Norm einen kleineren Wertebereich zur Verfügung stellen würde. Das Problem mit solch einem Programm ist, daß es dann nicht mehr gemäß der Norm arbeitet, sondern gemäß der Eigenschaften einer speziellen Umgebung. Weil diese Eigenschaften aber nicht durch die Norm garantiert werden, kann es sein, daß solch ein Programm unter einer anderen Umgebung dann nicht mehr funktioniert.

Wenn ein Programm viele solcher Abhängigkeiten von der Umgebung hat, dann wird es recht mühevoll, sie alle zu suchen und zu beheben, weswegen es sich empfiehlt, gleich von Anfang an maximal portabel  zu programmieren, das heißt so, daß ein Programm unter jeder normgerechten Umgebung  läuft. Das bedeutet, sich von speziellen „Erweiterungen“, „Toleranzen“ oder anderen Eigenschaften einer speziellen Umgebung nicht abhängig zu machen. Es bedeutet weiterhin, daß der Programmierer die Norm kennen muß, weswegen jeder, der ernsthaft in einer bestimmten formalen Sprache schreiben will, Zugriff auf eine Exemplar der Norm benötigt.

In dem genannten Beispiel ist ein C -Programm also hinsichtlich des int-Wertebereiches maximal portabel, wenn es nur davon abhängt, daß dieser von −32767 bis +32767 reicht, weil die Norm nur diesen Wertebereich unter allen  Umgebungen garantiert.

Aber warum sollte ein Quelltext überhaupt maximal portabel sein? Tatsächlich kann es legitim sein, einen Quelltext zu schreiben, der nur unter einer ganz bestimmten Umgebung läuft und nicht mehr maximal portabel ist. Allerdings sollte das nur dann geschehen, wenn es erforderlich ist, weil es sonst ein Mangel wäre, ohne Notwendigkeit auf die Portabilität zu verzichten. Auf jeden Fall muß der Programmierer wissen, was er will (maximal portabel oder umgebungsspezifisch programmieren) und in der Lage sein, das bewußt umzusetzen.

In einem Lehrtext zu einer formalen Sprache sollte die maximal portable Verwendung im Vordergrund stehen, denn wenn man darin Programmiertechniken behandelte, die nur unter einer ganz speziellen Umgebung funktionieren, würde man damit vom Thema abweichen. Dann würde man nicht mehr die formale Sprache lehren, sondern die Verwendung ganz bestimmten Umgebung. Das ist natürlich auch legitim, sollte dann aber schon im Titel klar zum Ausdruck kommen.

Tests

Im Falle von abstrakten Sprachen kann die maximal portable Korrektheit eines Quelltextes nicht dadurch ermittelt werden, daß der Quelltext unter einer bestimmten Umgebung getestet wird und dort „funktioniert“. Denn es könnte sein, daß der Quelltext von bestimmten Eigenschaften der Umgebung abhängt, wie etwa einem erweiterten int-Bereich, die gar nicht durch die Spezifikation der formalen Sprache garantiert werden. Der Programmierer muß also die Spezifikation kennen und beachten, auch wenn Abweichungen unter einer bestimmten Umgebung nicht zu beobachtbaren Fehlern führen.

Wenn ein Quelltext unter einer bestimmten Umgebung einen gewünschten Zweck erfüllt, bedeutet das noch nicht, daß er gemäß der Sprachdefinition maximal portabel oder überhaupt sinnvoll ist. Die Korrektheit eines Programmes kann nicht  dadurch belegt werden, daß es unter einer bestimmten Umgebung läuft. Der Autor muß vielmehr die Spezifikation der formalen Sprache kennen und sich davon überzeugen, daß sein Quelltext entsprechend dieser Spezifikation den gewünschten Sinn hat.

Beispielsweise verlangt die Programmiersprache C++  bei der Verwendung bestimmter Teile der Standardbibliothek bestimmte Einfügedirektiven, wie etwa "#include <iostream>". In guten Lehrtexten zu C++  enthalten die normgerechten Beispielprogramme alle nötigen Einfügedirektiven. Einzelne Leser vergessen dann manchmal eine Einfügedirektive und stellen fest, daß das Programm dann trotzdem noch funktioniert. Das ist in Einzelfällen möglich, aber die Sprache garantiert dies eben nicht, und es kommt in Folge solcher Fehler dann auch manchmal zu schwer diagnostizierbaren Fehlern. Daher ist es falsch, obwohl es auf den ersten Blick „funktioniert“.

Manchmal ergibt sich keine Fehlermeldung, weil eine Kopfdirektive selber weitere Kopfdirektiven zur Folge hat, unter denen sich auch die benötigte befindet, aber daß dies so ist, wird nicht durch die Spezifikation der Sprache beschrieben, sondern ist nur eine Eigenschaft einer Implementation. Außerdem kann es auch sein, daß das Fehlen einer benötigten Kopfdirektive nicht zu einer Fehlermeldung führt, sondern—ganz im Gegenteil—dazu, daß ein anderer Fehler nicht  erkannt wird. Dann „funktioniert“ das Programm, aber gerade das ist  der Fehler. Ein solches Programm könnte unter Umständen falsche Ergebnisse liefern oder sich falsch verhalten.

So ist auch Bartosz Milewski  zu verstehen, wenn er sagt „Die Tatsache, daß das Programm funktioniert, ist ohne Bedeutung.“. Tatsächlich kann die Korrektheit eines Quelltextes einer abstrakten Sprache nicht durch Ausprobieren unter einer bestimmten Umgebung ermittelt werden, sondern nur an Hand der Norm.

Hinzu kommt auch noch, daß ein Programm zwar funktionieren könnte, aber gravierende stilistische Mängel enthalten kann, die es beispielsweise sehr erschweren, das Programm zu verstehen, zu erweitern oder möglichst allgemein einzusetzen. Auch solche Mängel kann man nicht durch Ausprobieren finden, sondern nur durch Verständnis der normgerechten Interpretation des Quelltextes. Gute Quelltexte entstehen nicht dadurch, daß man solange an ihnen herumbastelt, bis sie anscheinend „funktionieren“, sondern dadurch, daß sie von Anfang an auf Grundlage der durch die Norm definierten Syntax und Semantik ihrer formalen Sprache so konstruiert werden, daß sie die gewünschten Zwecke erfüllen. Daher gehört zum Erlernen einer durch eine Norm definierten formalen Sprache auch nicht nur das Einüben der Verwendung dieser Sprache, sondern auch das Erlernen der Sprache durch Lektüre der die Sprache definierenden Norm und mit der Norm verträglicher Lehrtexte.

Zusammenfassung

Eine formale Sprache wird nicht durch das Verhalten und die Eigenschaften einer bestimmte Implementation oder mehrere Implementationen definiert, sondern durch eine maßgebliche Spezifikation (Norm). Ein Quelltext ist nicht dann korrekt, wenn er von einer bestimmten Implementation oder von mehreren Implementationen akzeptiert wird, sondern wenn er das Gewünschte entsprechend der von der Norm festgelegten Syntax und Semantik der formalen Sprache zum Ausdruck bringt.

Seiteninformationen und Impressum   |   Mitteilungsformular  |   "ram@zedat.fu-berlin.de" (ohne die Anführungszeichen) ist die Netzpostadresse von Stefan Ram.   |   Von der Stefan-Ram-Startseite ausgehend finden sich oft noch mehr Informationen zu Themen, die auf einer Seite angesprochen wurden. (Eine Verbindung zur Stefan-Ram-Startseite befindet sich ganz oben auf dieser Seite.)  |   Der Urheber dieses Textes ist Stefan Ram. Alle Rechte sind vorbehalten. Diese Seite ist eine Veröffentlichung von Stefan Ram. slrprd, PbclevtugFgrsnaEnz