Wenn alter mit neuem C++-Code gemischt wird (was bei größeren Projekten
praktisch immer der Fall ist) und ich die Wahl habe, verwende ich die
alte Syntax, damit der Gesamtcode nicht in Kauderwelsch ausartet¹.
Außerdem schließe ich mich diesbezüglich Peters Meinung an:
Peter schrieb:
> Bei 4) finde ich dedizierte Typedefs/alias besser, da im Produktivcode
> der Typ des Function pointers erfahrungsgemäß mehrmals vorkommt, z.B.
> bei Callbacks oder im Testcode. Über einen eigenen Namen kann man einen
> Callback besser zuordnen und braucht bei Bedarf nur das typedef/alias zu
> ändern.
Damit stellt auch die etwas verschlungene Typsyntax von Funktionszeigern
kein Problem dar.
Dass man für den Return-Typ in Lambda-Ausdrücken eine andere Syntax
braucht, ist nicht besonders schön, aber auch nicht so tragisch, da die
Lambda-Ausdrücke ohnehin schon eine spezielle Syntax haben. Man könnte
allenfalls die Lambdas komplett ablehnen, was ich aber nicht tue, weil
damit endlich ein wichtiges Feature eingeführt wurde, das eigentlich
schon lange vor C++11 überfällig war.
Rust verwendet ja eine ganz ähnliche Syntax für Funktionsdeklarationen:
C++:
1 | auto myfunc(int n) -> double { ... }
|
Rust:
1 | fn myfunc(n: i32) -> f64 { ... }
|
Die Unterschiede:
- In Rust gibt es nur die trailing Syntax, also keinen Kauderwelsch.
- Rust verwendet auch für Variablendeklarationen die trailing Syntax
(mit einem ":" statt des "->" wegen der etwas anderen Bedeutung).
Deswegen passen die trailing Return-Types gut zur restlichen Syntax
von Rust, während sie in C++ sie eher wie ein Fremdkörper wirken.
- Während die Deklaration in C++ mit einem "auto" beginnt, das ja
eigentlich ein Platzhalter für einen Typ ist, aber – wie du oben
schriebst – auch als Function-Introducer gelesen werden kann,
verwendet Rust einen echten Function-Introducer "fn", mit dem jede
Funktionsdeklaration eingeleitet wird.
Bernd K. schrieb:
> Besser alte Zöpfe ganz abschneiden,
Das wird in C++ nicht mehr geschehen. Deswegen habe ich mir im
Nachbarthread ein C++2 gewünscht, das zu C++ ähnlich, aber nicht
abwärtskompatibel ist und alle bekannten Unstimmigkeiten beiseite
schafft.
Programmierer schrieb:
> C++ ohne Abwärts-kompatibilität ist Rust.
Rust unterscheidet sich von C++ schon sehr stark, hat aber IMHO von
allen derzeitigen Programmiersprachen das größte Potential, irgendwann
C++ zu ersetzen.
Bernd K. schrieb:
> komplett und konsequent auf Pascal-Grammatik (postfix type) umstellen
Ich persönlich finde die Typsyntax, wie sie von Ritchie geschaffen
wurde, gar nicht so schlimm. Sie ist zwar etwas gewöhnungsbedürftig,
aber in sich konsistent. Das änderte sich erst mit der Einführung von
- const (ANSI-C)
- Referenzen (C++)
- Rvalue-Referenzen (C++11)
- trailing Return-Types (C++11)
> und schon werden auch die Funktionszeiger wieder entknotet und lesbar
> (von links nach rechts parsbar).
Wenn man für die Funktionszeiger – wie von Peter empfohlen – Typsynonyme
(in C mit typedef) nutzt, verschwinden die Knoten. In Pascal ist die
Verwendung von Typsynonymen im Zusammenhang mit Funktionszeigern sogar
vorgeschrieben, vermutlich um überlange Typspezifikationen zu vermeiden.
In C++ kann man zudem oft lange und komplizierte Typspezifikationen in
Deklarationen durch "auto" zu ersetzen. Das ist zwar keine vollwertige
Type-Inference wie bspw. in Haskell, hilft aber in vielen Fällen, den
Code übersichtlicher zu gestalten.
Gerade für die Verwendung von Funktionen als First-Class-Objekte (also
für die funktionale Programmierung, für die derzeit ein wachsender Trend
zu erkennen ist) hat C++ mittlerweile sehr viel mehr zu bieten als Free
Pascal. In Free Pascal sind wohl diesbezüglich auch Entwicklungen im
Gange, aber da wird man wohl noch eine Weile auf die Ergebnisse warten
müssen.
————————————
¹) Aus demselben Grund bevorzuge ich auch die Initialisierung mit = oder
() anstelle des neuen {} (s. Nachbarthread zur Brace-Initialization).