T.M. schriebDer Sinn eines solchen will sich mir beim besten Willen nicht erschliessen. Ich schreibe nicht jeden Tag eine solche Schleife zum Lesen einer Datei, nicht einmal jede Woche, nicht einmal jeden Monat, obwohl ich 8 Stunden jeden Tag C++ mache. Wozu soll die Sprache da ein Statement anbieten? Das ist irgendwie albern, ehrlich.
Damit habe ich fast gerechnet. Also, zunächst geht es nicht allein um das bereitstellen eines FD, das war lediglich ein sehr einfaches Beispiel um Dir eine Lösung wenigstens theoretisch irgendwie möglich zu machen.
Hast Du auch beim hello-world gesagt: "Warum um alles in der Welt sollte ich 'Hello' auf einem Bildschirm ausgeben wollen?" Natürlich ging es nicht um das Hallo.
Die Schleife ist auch in diesem Beispiel gar nicht gegenstand der Aufgabe, im Body dieses Statements könnte /jeglicher/ Code stehen. Die Schleife mit zu abstrahieren wäre wahrscheinlich Blödsinn. (Wobei man ja nie weiss, ob mans mal braucht. Brauchte ich es, wäre es kein Problem, es in ein paar Zeilen zu implementieren.)
Gut, ich glaube Dir, dass Du sehr selten den Beispielcode brauchst, aber wenn Du mir allen Ernstes sagen willst, dass es in deiner Arbeit keinen Boilerplate gibt, dann kann ich das nicht glauben. Das von mir angeführte Beispiel steht für /alle/ wiederholt anfallenden Codemuster, nicht nur für dieses kleine Beispiel.
In Sprachen, die das ermöglichen /gibt/ es keinen Boilerplate, den man nicht freiwillig toleriert (was meist nicht passiert).
Und wieder genau die Einstellung, gegen Die ich argumentiere: Ich will eben /nicht/, dass C++ dieses Statement bekommt. Genau das ist der Knackpunkt. Der Sinn der Sache ist, dass Du Dir solch ein Statement bequem beim ersten erkennen sich wiederholender Muster in Deinem Code /selbst/ erstellen kannst.
Zu Deinen acht Stunden Arbeit: Ich glaube Dir, dass Du ein Fähiger Programmiere bist, wohl auch über C++ hinaus, aber beantworte mir eine Frage: Wenn Dir diese Möglichkeiten auch nur eine Stunde am Tage ersparten (was vorsichtig geschätzt ist, wenn Du an diese Abstraktionsmöglichkeiten gewöhnt bist, fallen Dir täglich Dinge auf, die eigentlich nur "Ritual" sind), hätte es sich dann nicht schon dicke gelohnt? Meine Antwort wäre "ja".
Um es anders auszudrücken: Du benutz einen Compiler, einen Übersetzer, musst aber in Deiner Sprache sehr viel Arbeit, für die dieser Übersetzer eigentlich da sein sollte, zumindest könnte, selbst übernehmen, weil Du keine (benutzbare) Möglichkeit hast, ihn auf deine Anforderungen hin zu optimieren.
Also erstens wird das Schliessen in meinem Fall vom Destruktor erledigt. Und der implizite Aufruf eines Destruktors *ist* ein syntaktischen Konstrukt, übrigens bemerkenswerter Einfachheit. Ich sagte ja, dieses Schnipsel sei dicht. Zwotens ging es um einen geöffneten Filedeskriptor, ich nehme also an, dass der dann auch offenbleiben soll. Die Destruktoren der generischen stream-Klassen machen das in diesem Fall auch so. Drittens, wenn Du Code haben willst, der eine vernünftige Fehlerbehandlung durchführt (exceptions), dann will ich gerne mal sehen, wie das Dein eines Statement macht.
Wie oben angeführt: Ok, in diesem Falle musst Du nicht hinterher aufräumen, also bleibt es bei deinem ersten Snippet, aber auch ohne den try/finally block ist und bleibt es Boilerplate. Ich schätze Dich als schlau genug ein, dass Du besseres mit dieser Zeit anfangen könntest.
Was nun, wenn das zu abstrahierende Muster nicht vier Zeilen umfasst, sondern zehn? Wo ist die Grenze, ab der Du zugestehst, dass man solchen Kram nicht von Hand schreiben sollte?
(Muster wie gesagt im textuellen sinne, nicht im Sinne von "Entwurfsmuster".)
Einschub: die exception-Behandlung in C++ ist tatsächlich verbesserungsbedürftig. Es mangelt insbesondere an einem Konstrukt, vor bzw. hinter die Anweisung, die die exception ausgelöst hat, zu springen, um die Anweisung (ggf. nach Änderung äusserer Bedingungen) neu auszuführen oder zu überspringen. Aber welche Sprache kann das?
Common Lisp. Selbst, wenn wir nicht das beste Condition-System hätten, dass mir je unter die Augen gekommen ist, könnte ich es mir (relativ) mühelos erstellen; mit eben den Mitteln, deren Sinn sich Dir (noch) verschließt.
Der Aufwand besteht genau in obigem Schnipsel mit dem einen Unterschied, dass eine andere stream-Klasse verwendet werden muss, wenn man einen geöffneten Filedeskriptor verwenden will.
Nochmal: Es geht nicht um irgendwelche Stream-Klassen, sondern darum, dass Du Sachen von Hand schreiben musst, sich wiederholende Muster, nicht abstrahieren kannst. Eine if Anweisung wird in Sprünge übersetzt; würde es Dir etwas ausmachen, diese Sprünge heutzutage noch von Hand zu schreiben? Das Beispiel ist Dir zu grobschlächtig? Ok. Wie ist es mit for-Schleifen, die über Datenstrukturen iterieren? Ist es nicht nett foreach blabla schreiben zu können (wie auch immer es in modernem C++ heißt), ohne sich um diesen Kram kümmern zu müssen? Nun geht es aber nicht um /ein/ spezifisches Konstrukt, sondern darum, dass Du Dir, nach Deinen Anforderungen die Abstraktionen schaffen kannst, die Dir hilfreich und sinnvoll erscheinen.
Mit ähnlichen Argumenten (Darf ich diese Paar Zeilen jetzt nicht mehr von Hand schreiben? Das ist doch schnell gemacht. Ich sehe den Sinn nicht ein) haben sich damals die alten Assembler-Hacker mit Händen und Füßen gegen Hochsprachen gewehrt.
danlei schriebWie siehts mit der zweiten Aufgabe aus?
Also erstens hab ich nebenbei auch noch irgendwie zu arbeiten. Zwotens bist Du noch schuldig, eine Sprache zu nennen, die das von Dir geforderte hoffentlich einzeilige Statement anbietet. Drittens scheint mir letzteres Problem eines zu sein, das durch Mehrfachvererbung halbwegs zu lösen sein sollte.
Meine Schuld hänge ich gleich an, keine Sorge.
Also, zur zweiten Aufgabe: Ich denke, dass sie in C++ nur sehr umständlich zu Lösen sein wird. Schuldig bist Du mir die Lösung nicht, vor allem, da du wahrscheinlich auch bei diesem Beispiel, wie auch in diesem Falle schon von mir vorausgesagt, seinen Wert nicht erkennen wirst. Warum? Allah.
Nur weil Du etwas in Deinem Arbeitsaltag nicht benutzt (wie auch, wenn Du die Möglichkeit nicht einmal kennst, geschweige den Sinn derselben) heißt das nicht, dass Dir nicht etwas jenseits der C++-Welt entgeht. Du kannst ob meines forschen Tones beleidigt sein, es vollkommen ignorieren, oder es Dir wenigstens im Hinterkopf behalten für Zeiten, in denen du deine Zeit nicht mehr mit Arbeit verschwenden willst, die der Compiler für Dich erledigen sollte.
Viertens allerdings nimmt die Diskussion nun einen Verlauf, der irgendwie weit abseits führt. Der Sinn ist mir nicht klar. Du magst C++ nicht. Das hast Du zum Ausdruck gebracht. Ich sage nicht, es sei der Weisheit letzter Schluss, und ich behaupte auch nicht, es sei wunder wie schön, aber ich sage, es ist weit entfernt von der durch Dich mit einiger Polemik postulierten Unbrauchbarkeit. Ich würd's dabei belassen.
Sinn? Sagen wir Missionierung, nur ohne das Ausbeuten. 🙂 Spaß beiseite: Dieser Artikel sollte sich freundlicher lesen, ich habs zumindest versucht.
Aber nun zu meiner Schuld:
(with-open-file (file "/foo/bar/baz")
...
...
...)
Eine einfache Implementierung:
(defmacro my-with-open-file ((var filename) &body body)
`(let ((,var (open ,filename)))
(unwind-protect
,@body
(close ,var))))
Und das war auch schon die ganze Geschichte, das letzte Mal, das ich Boilerplate zum Öffnen einer Datei und allem Drumherum geschrieben habe. (Hätte, wenn es nicht sowieso schon im Standard wäre.)
Nochmal zum Sinn der Sache:
Das ganze ist auf jegliche Art von Code anwendbar. Ein Beispiele für diese Art Abstraktion wären z.B. with-html-output, with-input-from-string. Kurz, alles, was einen Kontext etabliert. In nicht wenigen Fällen kann diese Art der Abstraktion (und diese schließt /nicht/ andere Abstraktionsarten wie OOP aus) sparen Dir Diese Dinge wirklich eine Heidenarbeit.
Damit ist die Sache aber noch nicht am Ende: Auch Kontrollstrukturen und ähnliches lassen sich so Implementieren. Weiter oben erwähntest Du, dass Du Verbesserungsbedarf im Exception-Handling begrüßen würdest. Nun, wenn mir mein Condition-System nicht gefiele, so würde ich es mit eben diesen Mitteln zu dem machen, was ich brauche.
Also, ich habe mir redliche Mühe gegeben, es zu erklären und bin für Fragen offen. Vielleicht habe ich ja erreicht, dass Du wenigstens in Erwägung ziehst, dass ich Dir keinen Unsinn verzapfe, sonder Du mir glaubst, dass ich von etwas rede, was ich als in einer Sprache wichtig erachte. Meine Hoffnung ist allerdings relativ gering, denn ich kann mich an Zeiten erinnern, als ich mit BASIC voll und ganz zufrieden war. (Eben bevor ich andere Sachen kennengelernt und ihren Sinn verstanden habe.)
Soviel zur syntaktischen Abstraktion. Die OOP-Aufgabe wäre auch noch interessant, aber das kannst Du halten, wie Du willst.