T.M. schriebDas Wort "Kontext" existiert in C++ nicht, weder als Begriff noch als Konzept. Das wollte ich noch hinzufügen. Es handelt sich ja dabei um den Zugriff auf ein implizit erzeugtes, anonymes Objekt. Man bemerkt vielleicht nicht einmal, daß überhaupt ein Objekt im Spiel ist, man rechnet auch nicht mit seiner Konstruktion sowie Destruktion (alles wichtige Dinge!).
Eben weil es nicht existiert und es hier um Metaprogrammierung geht, sollst Du es ja einführen. Was soll bitte der Punkt einer Metaprogrammierung sein, die es nicht erlaubt, neue Konzepte und Konstrukte einzuführen? Was den Begriff Kontext angeht, so ist er lediglich eine passende Beschreibung, nennen kannst Du das es gerne wie Du möchtest.
Ein wesentliches Problem dabei ist beispielsweise, welches Objekt ist gemeint, wenn sich zwei oder noch mehr "Kontexte" überlappen? (In C++ hat man ein solches Problem mit Namespaces und das ist verdammt lästig!) Was, wenn Du aus einer Datenbank lesen und die Daten in eine andere Datenbank schreiben willst? Dies ist nur über eindeutig benannte Objekte vernünftig zu machen, was ich auch nicht als Zunahme an Komplexität bezeichnen würde. Es ist schlicht ein Gebot der Vernunft.
In unserem konkreten Beispiel würde ein Kontext den anderen lexikalisch überlagern, richtig. Variablen gleichen Namens überlagern sich ebenfalls, benutzt Du auch sie deshalb nicht? In anderen Fällen (with-open-file) ist das erstens nicht der Fall, zweitens wäre es kein Problem, ähnlich wie bei with-open-file ein weiteres Argument einzuführen, welches die einzelnen Objekte jeweils referenziert. Problemlos. Bereits in dem Post, in welchem ich with-sql eingeführt habe, habe ich darauf hingewiesen, dass ich keine höheren Design-Überlegungen angestellt, sondern lediglich das geschrieben habe, was der Fragende wissen wollte. Ob man solch ein Makro nun so, oder so implementiert, bleibt jedem selbst überlassen. In eine andere DB das Ergebnis zu schreiben ist übrigens überhaupt kein Problem, da lexikalischer Skopus dies nicht ausschließt – trotzdem bleibt der Einwand im Grunde teilweise berechtigt, was diesen Konkreten Fall angeht. (Zum Beispiel gibts Leute, die awhen/aif (implizit Bindende Konditionale) lieben, andere hassen sie wegen er impliziten Bindung (sie benutzen explizit bindende bif/bwhen). Die Hauptsache ist: Alle bekommen, was sie wollen, weil die Sprache jegliche Abstraktion erlaubt. Metaprogrammierung eben.
Ein zweites Problem ist, daß man bei Verwendung solcher Kontexte leicht aus den Augen verliert, was eigentlich der Kontext ist, insbesondere wenn der Kontext mehr als eine Bildschirmseite umfaßt und seine Erstellung gerade nicht sichtbar ist oder auch, und dies ist ein sehr fieser Fall, wenn es sich um fremden Code handelt. Ich weiß dann gar nicht, woraus der Kontext eigentlich besteht, man sieht ihm ja nichts an, nicht einmal einen Typ.
Wenn man Funktionen, Makros, oder welcherlei Blöcke auch immer, auf über eine Bildschirmseite ausdehnt, hat man ohnehin schon ein Problem und nicht vernünftig abstrahiert, ganz einfach. Dass dies in Java und C++ üblich ist, sagt schon einiges über diese Sprachen aus.
Des Weiteren widersprechen ungefähr 50(!) Jahre Lisp-Geschichte Deinen Theorien. Selbst Python hat mit seinem with-Statement einen verkrüppelten Abklatsch dieser "Kontexte" eingeführt. Ganz im Gegenteil zu Deinen Annahmen erleichtern Makros das Lesen fremden Codes und die Verwendung enorm. Eine Funktion abstrahiert ebenfalls und Du siehst ihr von Außen nicht an, was sie tut, hast Du da auch die angesprochenen Probleme? Was Typen angeht: Lisp ist eine streng dynamisch getypte Sprache, das hat mit der Diskussion hier überhaupt nichts zu tun.
Also, bei aller Kritik, die Du hier einbringst (selbst wenn sie Substanz hätte, was ich bestreite): Wo liegt bitte das Problem dieses Konzept in C++ einzuführen, wenn es, wie Du sagst, Metaprogrammierung erlaubt und formbar ist? Genau darum dreht sich unsere ganze Diskussion.
Konkret: Kritik hin oder her, bist Du in der Lage das gewünschte Konstrukt mit Hilfe der C++ eigenen Mittel zu implementieren, oder nicht?
Da Dir auch dieses Beispiel nicht gefallen hat, liefere ich Dir gerne noch ein weiteres (und beliebig viele weitere, so es denn sein muss):
Wir haben keine Lust mehr, immer wenn wir etwas n mal wiederholen wollen
for(x = 0; x < n; x++) { <code>;* } zu schreiben, also möchten wir, als fähige Metaprogrammierer und Möchtegern-Sprachdesigner dieses Konzept abstrahieren. Wir führen ein syntaktisches Konstrukt repeat ein, welches den Boilerplate für uns übernimmt, und uns vor off-by-one Fehlern bewahrt.
(defmacro repeat (n &body body)
`(dotimes (_ ,n)
,@body))
Aufgerufen wird es folgendermaßen:
(repeat 5
(print 'hallo)
(print 'blabla))
Also, wie macht man das in C++?
(Anm.: Natürlich war das jetzt etwas zu einfach, da es ein, im Prinzip gleichwertiges, Konstrukt schon im Sprachkern gibt. Solltest Du eine Lösung sehen wollen, die von anderen Konstrukten abstrahiert, welche ähnlich zu C/C++s for aufgebaut sind, kann ich auch das gerne liefern.)
Noch ein Beispiel:
Wir möchten (bitte keine Diskussion, ob man das braucht, es geht darum zu zeigen, wie man neue Syntax schafft) eine Syntax erstellen, die alles innerhalb eckiger Klammern als Liste von Zahlen betrachtet und die Summe aller Elemente zurückliefert.
(defreadtable sum-bracket-syntax
(:merge :standard)
(:macro-char #\] (get-macro-character #\)))
(:macro-char #\[ #'(lambda (stream char)
(reduce #'+ (read-delimited-list #\] stream)))))
(in-readtable sum-bracket-syntax)
(Anm: Ich benutze hier
benannte Readtables, die nicht im Sprachstandard definiert sind. Gleiches ginge mit Standardmitteln, sprich normalen Readtables, aber ich betrachte diese aus modularen Gründen als die bessere Lösung)
DHL> [1 2 3 4 5 6 7 8 9 10]
55
Fertig. Nun magst Du anführen, dass [] in C++ schon belegt ist, aber eine Sprache, die zur Metaprogrammierung geeignet ist, hat mit so etwas keine Probleme. Sollte es doch Probleme dabei geben, kannst Du auch gerne andere Zeichen verwenden, sagen wir >> und <<.
Also, ich habe genug Beispiele gezeigt, wie eine Sprache die sich als geeinet für Metaprogrammierung versteht funktioniert und ich habe an Beispielen den Sinn dieser Möglichkeiten erläutert. Natürlich hast Du Bedenken und (teilweise berechtigte, teilweise durch Unkenntnis entstandene) Einwände, das ist auch ok. Trotzdem: Du hast nicht eine einzige der gestellten Aufgaben gelöst,
obwohl Du ein fähiger Programmierer bist. Mir persönlich sagt das: C++ ist zur Metaprogrammierung gänzlich ungeeignet und ich kann mir auch die nächsten zehn Jahre die Zeit sparen, mich damit zu beschäftigen. Gerne hätte ich mich auch vom Gegenteil überzeugen lassen. Gleiches gilt übrigens für das OOP-Beispiel.