Andererseits kann ein goto ein Programm auch einfacher und durchsichtiger machen, namentlich bei Programmverzweigungen (if/switch o.ä.), nämlich wenn in einigen Zweigen zuerst eine spezifische "Vorbehandlung" erfolgt, auf die dann eine für mehrere Zweige gemeinsame "Haupt-" oder "Abschlussbehandlung" folgt, die etwa nur im letzten dieser Zweige hingeschrieben wird, während man aus den übrigen dieser Zweige nach der "Vorbehandlung" mit goto dort hin springt. |
Andererseits kann ein goto ein Programm auch einfacher und durchsichtiger machen, namentlich bei Programmverzweigungen (if/switch o. ä.), nämlich wenn in einigen Zweigen zuerst eine spezifische "Vorbehandlung" erfolgt, auf die dann eine für mehrere Zweige gemeinsame "Haupt-" oder "Abschlussbehandlung" folgt, die etwa nur im letzten dieser Zweige hingeschrieben wird, während man aus den übrigen dieser Zweige nach der "Vorbehandlung" mit goto dort hin springt. |
In SpracheLava verzichten wir sowohl auf "goto", als auch auf herkömmliche Programmschleifen (und damit zugleich auch auf die Mehrfachzuweisung von Werten an (Schleifen- und andere) Variablen; Rekursion, Quantoren und Single-Assignment-Variablen treten an ihre Stelle. Und dies löst in der Tat ein Problem: Es ermöglicht die statische Analyse des Datenflusses, der in Lava streng "von oben nach unten" im Programmtext verläuft. Man kann also immer leicht feststellen, wo der Wert einer Variablen "herstammt", d. h. wo im Programm er der Variablen zugewiesen wird. Während der goto-Verzicht den Kontrollfluss übersichtlicher gemacht hat, vereinfachen diese weitergehenden Maßnahmen in SpracheLava darüber hinaus auch die Analyse und Verstehbarkeit des Datenflusses und ermöglichen damit zugleich eine strenge Kontrolle der Initialisierung von Variablen. (Siehe auch http://www.sit.fhg.de/Lava/LavaDoc/html/RepetComputSamples.htm).
Andererseits kann ein goto ein Programm auch einfacher und durchsichtiger machen, namentlich bei Programmverzweigungen (if/switch o. ä.), nämlich wenn in einigen Zweigen zuerst eine spezifische "Vorbehandlung" erfolgt, auf die dann eine für mehrere Zweige gemeinsame "Haupt-" oder "Abschlussbehandlung" folgt, die etwa nur im letzten dieser Zweige hingeschrieben wird, während man aus den übrigen dieser Zweige nach der "Vorbehandlung" mit goto dort hin springt.
Alternativ kann man natürlich die "Hauptbehandlung" auch in eine eigene Funktion stecken, die dann am Ende aller dieser Zweige aufgerufen wird, wodurch das goto wieder entbehrlich wird.
Diese Abspaltung der "Hauptbehandlung" ist jedoch besonders dann nicht sehr natürlich, wenn die "Hauptbehandlungs-Funktion" auf lokale Variablen der Aufrufumgebung zugreifen muss, die dann eigens als Parameter übermittelt werden müssen. Dies lässt sich wiederum etwa dadurch vermeiden, dass man die "Hauptbehandlung" als Makro statt als Funktion ausdrückt, und dieses Makro am Ende jedes Zweiges einsetzt.
Diese unschöne Parameter-Übergabe kann aber auch durch etwas mehr Objekt-Orientierung vermieden werden: Man deklariert eine neue Objekt-Klasse, deren Membervariablen gerade die bisherigen lokalen Variablen sind und macht die "Hauptbehandlung" zu einer (dann parameterlosen) Methode dieser Klasse, die mit einem entsprechenden Objekt aufgerufen wird.
Ich denke, dass z.B. das /BeispielMicrocontroller auf diese Weise 1. ohne goto auskäme und 2. zugleich in sehr kurze, wesentlich übersichtlichere Teile (Verzweigungslogik, spezifische Vor- und gemeinsame Hauptbehandlungen) aufgegliedert werden könnte. Es ist eine andere Frage, ob die extremen Einschränkungen der Mikro-Controller-Programmierung eventuell zu einem mehr assembler-nahen Programmierstil mit vielen goto's und wenigen Functions zwingt.
Explizit sichtbare Makros gefallen mir deshalb nicht, weil sie ja eigentlich auf einer metasprachlichen Programmier-Ebene angesiedelt sind, wo sie beschreiben, wie der eigentliche Programmtext durch Operationen auf der makrosprachlichen Ebene erzeugt wird. Diese zwei Sprachebenen machen Programme nicht gerade übersichtlicher, leichter verstehbar und automatisch analysierbar (letzteres z.B. um die korrekte Initialisierung von Variablen zu überprüfen).
Anstelle einer Makrosprache würde ich in SpracheLava lieber den dortigen Struktureditor für ausführbaren Code so ausbauen, dass er das Benennen und das wiederverwendende Referieren von Code-Passagen in besonderer Weise unterstützt, so dass die referierten Passagen an der Referenzstelle (wo bei Makro-Verwendung nur der Makro-Aufruf stünde) direkt "eingeblendet" wird. Die gleiche Idee könnte darüber hinaus auch für eine Technik der "inkrementellen Spezialisierung" von Klassen-Methoden verwendet werden (siehe den entsprechenden Abschnitt in meinem Artikel http://www.sigs-datacom.de/sd/publications/pub_article_show.htm?&AID=442&TABLE=sd_article im OBJEKTspektrum.)
Generell sehe ich herkömmliche Programmvariablen und goto als begriffliche Relikte aus der Zeit der Assembler-Programmierung (adressierbare Speicherplätze, Instruction-Counter (IC), Sprungbefehle, die den IC auf eine neue Befehlsadresse setzen). Die experimentelle SpracheLava kann als Versuch vertanden werden, diese Relikte vollständig durch mehr mathematisch-logische Begriffe zu ersetzen: Lava-Variablen sind keine adressierbaren Speicherplätze mit wechselndem Inhalt, sondern "Unbestimmte" im mathematischen Sinn, deren mögliche Werte durch automatisch auswertbare/ausführbare mathematisch/logische Bedingungen spezifiziert werden. Schleifen werden teils durch Rekursion, teils durch All- und Existenz-Quantoren ersetzt. Lava soll demonstrieren, dass dies auf intuitiv eingängige Weise machbar ist, ohne dem Programmierer allzu viel Umdenken und Lernaufwand abzuverlangen.
Soweit ich das verstehe, wendet sich GoToConsideredHarmful gar nicht unbedingt gegen jegliche Verwendung von goto, sondern nur gegen die undisziplinierte, z. B. um unkontrolliert in Blöcke hineinzuspringen etc. (man denke an frühe Basic-Programme, die man verbrochen hat ... ;)
Genau genommen gibt es ja in vielen Sprachen wie z. B. der SpracheJava auch noch "abgespeckte" goto Befehle (break/continue o. ä.), die halt die Änderung des Kontrollflusses nur in ganz bestimmten Dimensionen zulassen. -- IljaPreuß
Ich habe mir das "goto" nie verboten, allerdings habe ich es in den letzten 10 Jahren auch nie gebraucht. Alternativen gibt es ja genügend: break, return und throw ersetzen "goto" in allen praktischen Fällen.
Beispiele |
Da fällt mir ein, in der SpracheIntercal gibt es kein GOTO, aber dafür ein ComeFrom.
10 tue irgendwas 20 tue nochwas 30 tue etwas mehr[...] und dann irgendwo
1000 come from 20