Stroutrupinterview
-
!rr!rr_. schrieb:
Mach einen Gegenvorschlag, der kein neues Schlüsselwort einführt, welches eine hohe Kollisionsgefahr mit Funktions-/Typ-/Variablen-Namen bereits existierender C++ Programme hat.
Nur Meckern ist ja einfach.
-
krümelkacker schrieb:
!rr!rr_. schrieb:
Mach einen Gegenvorschlag, der kein neues Schlüsselwort einführt, welches eine hohe Kollisionsgefahr mit Funktions-/Typ-/Variablen-Namen bereits existierender C++ Programme hat.
Nur Meckern ist ja einfach.
Waere ein neues Schluesselwort wirklich so schlimm? Im schlimmsten Fall muss man einmal Suchen+Ersetzen machen und neukompilieren.
-
Und welches Schlüsselwort?
-
wie wär's mit so einer Notation für lambada-Funktionen?
/\ int x /\ float y { x + y; }
mnemonisch schön.
- oder eben ein neues Schlüsselwort, "lambda" würde sich da anbieten. Um Kollisionen zu vermeiden, vielleicht alternativ _lambda_ oder __lambda__.
Ich würde favorisieren, für anonyme Funktionen die bereits vorhandene Schreibweise für benannte Funktionen zu benutzen, nur mit einem speziellen Namen, etwa
__(int x, float y){ return(x + y); }
oder
O(int x, float y){ return(x + y); }
oder so . aber ich bin kein Sprachen-Designer und muß mir deshalb
auch keine Gedanken darüber machen
-
Besser fände ich auf Lambda Funktionen ganz zu verzichten und dafür lokale Funktionen einzuführen. Da man Lambda-Ausdrücke mit explizit typisierten Parameter eh nicht in eine Zeile kriegt vermute ich, dass die häufigste Anwendung dafür mit auto Hand in Hand gehen wird:
auto foo = [=](int x){return x*x;}; bar(1,2,3,5,4,foo);
Was an sich eine lokale Funktion ist.
-
Naja, aber mit Lamda-Funktionen kann man schon schöne Dinge machen. Z.B. ein schöneres for-each:
vector<int> ivec(10); for_each(ivec.begin(), ivec.end(), [&](int i) { /* Mache etwas mit i */ });
Selbiges geht natürlich auch für viele andere Höhere Funktionen aus <algorithm>.
Ich würde favorisieren, für anonyme Funktionen die bereits vorhandene Schreibweise für benannte Funktionen zu benutzen, nur mit einem speziellen Namen, etwa
Diese ganzen Beispiele kommen aber nicht an die Mächtigkeit der C++0x Version heran, weil einfach die Capture-clause (also das in den []) fehlt.
Anfangs fand ich die neuen Lamdas auch hässlich, aber sobald man sich mal ein bisschen damit beschäftigt ist es ganz natürlich und sinnvoll.
-
die capture clause [...] könnte entfallen, wenn man sich per Default für alle Bindungen auf "by reference" einigen könnte.
-
Aber integrale Typen wie ints würdest du wohl doch lieber by value haben, oder? In C++ gehts ja immer um minimalen Overhead...
-
die capture list wäre ja gar nicht nötig, wenn man anonyme Funktionen
wie gewöhnliche Funktionen schreiben könnte, nur eben mit einem reservierten
Namen.Spezifikation von "by value / by reference" könnte dann nämlich in der Liste der formalen parameter stehen:
O(foo &x, bar y){ return x + y; }
-
!rr!rr_. schrieb:
die capture list wäre ja gar nicht nötig, wenn man anonyme Funktionen
wie gewöhnliche Funktionen schreiben könnte, nur eben mit einem reservierten
Namen.Was hat das eine mit dem anderen zu tun?
!rr!rr_. schrieb:
Spezifikation von "by value / by reference" könnte dann nämlich in der Liste der formalen parameter stehen:
O(foo &x, bar y){ return x + y; }
Was hat das denn mit dem zu tun, was man durch die capture-clause erreichen will? Ich habe ein bisschen den Eindruck, als würdest Du das Konzept der capture-clause nicht verstehen.
-
!rr!rr_. schrieb:
die capture clause [...] könnte entfallen, wenn man sich per Default für alle Bindungen auf "by reference" einigen könnte.
Kann man sich aber nicht. Jedenfalls gefällt mir Dein vorschlag so gar nicht. Denk mal an so Sachen wie std::async. Einige Funktionsobjekte sollten schon ihre eigenen Kopien mitschleppen.
-
krümelkacker schrieb:
Was hat das eine mit dem anderen zu tun?
ich habe es geahnt
-
ach, jetzt weiß ich, was du meinst
- ja, nein, wieso genau müssen denn Variablen des äußeren Kontexts überhaupt spezifiziert werden, um sie in der anonymen Funktion zu verwenden? Ihre Sichtbarkeit würde ausreichen, um sie innerhalb der anonymen Funktion zu lesen und/oder ändern.
-
ok, jetzt hab ich's.
O(outer foo &x, outer int y, float z){ x = bla; return y + z; }
wobei:
O = reservierter Name für anonyme Funktionen
outer => "Zugriff auf äußeren Kontext"
outer foo &x => "capture by reference"
outer int y => "caputere by value"Damit könnte die herkömmliche Schreibweise
für benannte Funktionen einfach weiterverwendet werden.
-
Das könnte die Signatur aber ziemlich ausarten lassen. Ich find's aktuell ganz gut gelöst, ein "[&]" ist ja kurz und knackig.
-
!rr!rr_. schrieb:
ok, jetzt hab ich's.
O(outer foo &x, outer int y, float z){ x = bla; return y + z; }
Damit könnte die herkömmliche Schreibweise
für benannte Funktionen einfach weiterverwendet werden.Was ist denn mit dem Rückgabetypen? Den kann man zZ ja nur weglassen, wenn der Funktionskörper ein einziges "return ...;" ist. Die "capture-clause" hier in den ()-Klammern unterzubringen gefällt mir gar nicht. Das sollte man schon trennen. "O" und "outer" als Schlüsselwörter zu verbraten, ist IMO auch keine gute Idee.
So, wie es aktuell aussieht, gefällt es mir viel besser:
[&x,y](float z)->float{ x=bla; return y+z; }
Ich muss den Typ von x und y nicht noch extra angeben. Der ist dem Compiler ja schon bekannt. Außerdem sehe ich hier sofort, wieviele Parameter der Funktionsaufruf-Operator erwartet.
Bzgl "anonyme Funktionen", der aktuelle Entwurf erlaubt eine Konvertierung eines Lambdaausdrucks zu einem Funktionszeiger, falls das "effective capture set" leer ist. Wenn ich das richtig verstehe, soll dann folgendes funktionieren:
void foo(void(*funptr)()) { funptr(); } int main() { foo([]{ cout << "hello world!\n"; }); }
Das einzige, was ich ein bisschen vermisse, ist ein "move-capture". [&x] bedeutet, dass das Funktionsobjekt eine Referenz auf x speichert. [y] bedeutet, dass das Funktionsobjekt eine Kopie von y speichert. Da wir aber auch "move-only"-Typen in C++ haben werden (wie zB streams, unique_ptr, unique_lock, etc) und mit Move-Konstructions Zeit sparen können, wäre es nett gewesen, wenn wir auch eine Syntax hätten, die ein Objekt nicht kopiert, sondern "move"t.
-
krümelkacker schrieb:
So, wie es aktuell aussieht, gefällt es mir viel besser:
[&x,y](float z)->float{ x=bla; return y+z; }
Haskell-Fans werden sich mit dem "->" wie zu Hause fühlen
Bei herkömmlicher Syntax kann man den Rückgabetyp doch auch angeben:
float O(outer foo &x, outer int y, float z){ x = bla; return y + z; }