From 5175f54a826e6b32edac76cad3f4dffad9da0220 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Thu, 23 May 2024 20:23:35 +0200 Subject: [PATCH] =?UTF-8?q?Antrag=20f=C3=BCr=20den=20Vortrag=20aus=20dem?= =?UTF-8?q?=20Konzept=20entwickelt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Kurzfassung - Langfassung --- FrOSCon24/Antrag.txt | 101 ++++++++++++++++++++----------------------- 1 file changed, 48 insertions(+), 53 deletions(-) diff --git a/FrOSCon24/Antrag.txt b/FrOSCon24/Antrag.txt index be079a0..de3e56a 100644 --- a/FrOSCon24/Antrag.txt +++ b/FrOSCon24/Antrag.txt @@ -1,12 +1,26 @@ -Konzept für einen Vortrag -========================= +Antrag für einen Vortrag auf der FrOSCon 24 +=========================================== :author: Ichthyostega -:date: 15.5.2024 +:date: 23.5.2024 Alt werden mit C++ ------------------ +Kurzfassung +~~~~~~~~~~~ + +Für eine langlebige Codebasis ist der Charakter und die weitere Entwicklung der einmal gewählten +Programmiersprache bedeutsam. Dies wird verdeutlicht anhand von Beispielen und Erfahrungen im Projekt +Lumiera mit der Sprache C++. Diese Sprache bietet Abstraktionsmittel, die sehr hilfreich sein können, +in einer großen und komplexen Codebasis die Flexibilität und Änderbarkeit zu erhalten. Allerdings tritt +die schrittweise Evolution dieser Sprachmittel in Wechselwirkung mit der Entwicklung der Codebasis und +erzeugt Wartungsprobleme. Dies wird beleuchtet am Beispiel von Lambdas und Funktoren, der Einführung +von RValue-Referenzen, sowie der Entwicklung von Generics und Concepts. + + +Langfassung +~~~~~~~~~~~ Software lebt solange sie änderbar ist. Für langlebige Software ist der Charakter der Programmiersprache bedeutsam. Der Charakter jeder Sprache, @@ -16,11 +30,9 @@ bestehenden Codebasis, die sich ebenfalls weiterentwickelt. Exemplarisch sei dies am Beispiel der Erfahrungen im Projekt Lumiera mit der Sprache C++ nachgezeichnet. In diesem OpenSource-Projekt wird Software für professionellen Film/Videoschnitt entwickelt. -Entscheidung für eine Plattform ist im Kern eine Entscheidung für ein Ökosystem. -Ein langlebiges Projekt muß auf Autonomie und Handlungsfähigkeit achten. -Daher scheiden die meisten zunächst offensichtlichen und beliebten Plattformen aus. - -Für Lumiera hat man sich damals für C++ in einem Unix-Umfeld entschieden. +Entscheidung für eine Plattform ist im Kern eine Entscheidung für ein Ökosystem. Ein langlebiges Projekt +muß auf Autonomie und Handlungsfähigkeit achten. Daher scheiden die meisten zunächst offensichtlichen und +beliebten Plattformen aus. Für Lumiera hat man sich damals für C++ in einem Unix-Umfeld entschieden. Realistische andere Optionen wären noch gewesen: D, Java, plain-C, Haskell. Einmal getroffen, ist eine solche Entscheidung mehr oder weniger endgültig. Denn jede der großen Programmiersprachen steht auch für eine bestimmte @@ -33,42 +45,25 @@ zu verstehen und zu beherrschen. Das wird ermöglicht durch den sachgemäßen An von Abstraktionen. Durch einen Interface-Kontrakt wird die Implementierung zum Detail, und damit lokal -änderbar. Sprachmittel: Vererbung. Tendentiell problematisch, aber gut verstanden -und weitgehend stabil. Tendenz: zunehmende Betonung von Modularität in Kontrakten, -realisiert als Mix-in - -Schwachstelle von Kontrakten: man muß das Verhalten festlegen. Damit dringt man in -die Implementierung ein und braucht entsprechende Ausdrucksmittel. Der vorherrschende -Ansatz hierfür war in den letzten 20 Jahren die Trennung von Infrastruktur und Funktionalität. -Ein Stück Funktionalität wird zu einem abstrakten Element, das in einen Kontrakt eingebunden -werden kann. - -Die Sprachmittel in C++ waren dafür wenig geeignet und problematisch: im Grunde haben wir -bis heute nur Funktions-Pointer. Jedoch hat C++ durch seine Klassen und das Typsystem eine -ausgeprägte Stärke im Bauen neuer Abstraktionen. Die Boost-Libraries haben daraus ein neues -Sprachmittel geschaffen: Funktions-Objekte. - -In der Praxis war der Weg dorthin mühsam und erforderte viele work-arounds. Das führt dazu, -daß im bestehenden Code eine Menge von Hilfsmitteln entsteht, die aufeinander aufbauen und -weithin im Einsatz sind. Und dann kam C++11 mit einem neuen Sprachmittel: den Lambda-Ausdrücken. -Diese stehen gleichberechtigt neben den Funktionsobjekten. -Unterschiede Funktions-Objekt vs Lambda. - -Die Entkopplung von Infrastruktur und Funktionalität führt dazu, daß zunehmend auch die -Operationen von den Daten entkoppelt werden müssen. Ein Funktions-Objekt, das gut per Kontrakt -in eine Infrastruktur eingebunden ist, könnte viele weitere Anwendungen abdecken, wenn man es -von den konkreten Argument-Daten abstrahieren könnte. So entsteht die Forderung nach Funktionen +änderbar. Für einen Kontrakt muß aber auch das Verhalten festgelegt werden. Damit dringt +die Abstraktion in die Implementierung ein, und erfordert entsprechende Ausdrucksmittel. +Der vorherrschende Lösungsansatz hierfür war in den letzten 20 Jahren die Trennung von Infrastruktur +und Funktionalität. Ein Stück Funktionalität wird zu einem abstrakten Element, das in einen +anderweitig geregelten Kontrakt eingebunden werden kann. Einmal etabliert, könnte ein solches +Schema oft an weiteren Stellen angewendet werden, sofern man auch noch von den konkreten +Funktionsargumenten abstrahieren könnte. So entsteht die Forderung nach Funktionen auf generischen Argumenten. -Auch hierfür waren die vorhandenen Sprachmittel unzulänglich, und ziemlich clevere Tricks kamen -flächendeckend zum Einsatz: vor allem die partielle Spezialisierung von Templates. -Draus entsteht in einer größeren Code-Basis eine interne Binding-Schicht, die erhebliche -Probleme bei der Wartung aufwirft. - -Währenddessen entwickelte sich die Sprache weiter. Mithilfe der RValue-References wurde das -transparente Durchreichen von Argumenten möglich. Die hierfür notwendigen semantischen Anpassungen -sind subtil und tückisch. Eine schrittweise Umstellung einer großen Codebasis ist ein langlaufender -Vorgang und eine organisatorische Herausforderung. +In der Praxis war der Weg dorthin mühsam und erforderte viele Workarounds. Die Sprachmittel in C++ +waren dafür anfangs wenig geeignet und problematisch: im Grunde gab es nur die schon in C nutzbaren +Funktions-Pointer. Jedoch hat C++ durch seine Klassen und das Typsystem eine ausgeprägte Stärke +im Bauen neuer Abstraktionen. Die Boost-Libraries haben daraus ein neues Sprachmittel geschaffen: +Funktions-Objekte. Mit C++11 wurden diese auch Teil der Sprachdefinition; zugleich jedoch wurden +auch Lambda-Ausdrücke als neues Sprachmittel eingeführt. Beide Sprachmittel stehen nun gleichberechtigt +nebeneinander und ermöglichen völlig neue Anwendungsmuster. Und die Sprache entwickelte sich weiter. +Mithilfe der RValue-References wurde das transparente Durchreichen von Argumenten möglich. Die hierfür +notwendigen semantischen Anpassungen sind subtil und tückisch. Eine schrittweise Umstellung einer großen +Codebasis ist ein langlaufender Vorgang und eine organisatorische Herausforderung. Oft muß man aber Argumente nicht nur durchreichen, sondern eine generische Funktion muß Eigenschaften ihrer Argumente verstehen und sich daran anpassen können. In den meisten älteren @@ -89,29 +84,29 @@ Trotzdem war diese Entwicklung in der Praxis derart erfolgreich, daß das C++ - gefolgt ist, und die Aufgabe übernommen hat, die historisch gewachsene schwarze Magie in klar definierte und sauber verwendbare Sprachmittel inkrementell weiter zu entwickeln. -- Varidadics +- Varidadische Ausdrücke - Concepts -Wenn man diese Aufgabe ernst nimmt, darf man sich nicht damit begnügen, einen pragmatischen Gebrauch +Wenn man diese Aufgabe ernst nimmt, kann man sich nicht damit begnügen, einen pragmatischen Gebrauch zu codifizieren und syntaktisch nett zu verpacken. Vielmehr sind neue Sprachmittel gefordert, die sich zwar in den Stil der Sprache nahtlos einfügen, und auch das gleiche leisten wie die historisch gewachsene Lösung, aber dennoch auf einer neuen Basis stehen, klar definiert und leichter korrekt verwendbar sind. Das ist eine sehr anspruchsvolle Aufgabe; das Ergebnis ist erstaunlich, hat aber -auch sehr lange gedauert und ist in einigen Teilaspekten immer noch unfertig. +auch sehr viel Zeit in Anspruch genommen und ist in manchen Teilaspekten immer noch unfertig. -Das bedeutet: man muß lange Zeit mit einer Mischung aus magischen Lösungen und der neuen -Standard-Lösung leben. Beide koexistieren, sind aber untereinander nicht kompatibel, obgleich -sie beide den gleichen Zweck erfüllen. Das erzeugt eine schwierige Situation in einer großen -Codebasis: zusammenhängende Systeme ziehen sich über weite Strecken durch den Code, und -stützen sich jeweils auf eine Menge von Hilfsmitteln ab, die untereinander nicht austauschbar -sind. +Diese schrittweise Weiterentwicklung der Sprache führt dazu, daß im bestehenden Code eine Menge von Hilfsmitteln +entsteht, die aufeinander aufbauen und weithin im Einsatz sind. Jedoch sind die Lösungen aus verschiedenen +Entwicklungsstadien untereinander oft nicht kompatibel, da sich die gesamte Herangehensweise geändert hat. +In einer größeren Code-Basis entstehen so komplexe interne Binding-Schichten, die erhebliche Probleme +bei der Wartung aufwerfen können: zusammenhängende Systeme ziehen sich über weite Strecken durch den Code, +und stützen sich jeweils auf Hilfsmittel ab, die untereinander nicht austauschbar sind. -Beispiele +Beispiele hierfür sind: - Loki-Typlisten vs. Variadic Arguments - Type-Traits vs. Concepts Da die jeweiligen Alternativen den gleichen Zweck auf unterschiedlichem Weg erreichen, kann eine -Umstellung herausfordernd sein und läuft auf eine Überarbeitung etablierter Infrastrukturen +Umstellung herausfordernd sein und läuft auf eine großflächige Überarbeitung etablierter Infrastrukturen hinaus. Daraus erwächst aber auch die Chance, in der Codebasis weithin etablierte Lösungen zu hinterfragen und weiterzuentwickeln.