Was sind die Vor- und Nachteile in den Ansätzen von C #, Java und Scala zu Closures / Lambdas /…?

30

Ich frage mich, was die technischen Implementierungsunterschiede zwischen C # und Scala sind und wie sich beide Lösungen im Vergleich zu den Implementierungsideen und -bedenken verhalten, die in der E-Mail Peek Past Lambda von Brian Goetz an die Mailingliste von Project Lambda (JSR 335) geäußert wurden .

Aus der E-Mail:

Wir untersuchten den Weg von "Vielleicht sollten Lambdas nur Instanzen der inneren Klasse sein, die wirklich einfach wären", kamen aber schließlich zu der Position "Funktionen sind eine bessere Richtung für die Zukunft der Sprache".

und weiter:

Die Sicht der Lambda-Objekte auf die Welt steht im Konflikt mit dieser möglichen Zukunft. Die Sicht der Lambdas-Are-Functions auf die Welt tut dies nicht, und diese Flexibilität beizubehalten, ist einer der Punkte, die dafür sprechen, Lambdas nicht mit dem Aussehen von Objektivität zu belasten.

Fazit:

Lambdas-are-Funktionen öffnen Türen. Lambdas-are-Objekte schließen sie.
Wir ziehen es vor, die Türen offen zu sehen.

Und ein Kommentar von einer Person im Reddit-Thread lautet:

Ich habe Neal Gafter darüber eine E-Mail geschickt, und nach meinem begrenzten Verständnis seiner Erklärung sind C # und das aktuelle Java-Design insofern ziemlich ähnlich, als Delegates tatsächlich Objekte und keine Funktionstypen sind. Anscheinend glaubt er, dass Java aus den Nachteilen von C # -Lambdas lernen und diese vermeiden sollte (ähnlich wie C # aus den Nachteilen von Java gelernt und sie am Anfang vermieden hat).

Warum bietet der Ansatz "Lambdas-Are-Functions" in Zukunft mehr Möglichkeiten als "Lambdas-Are-Objects"? Kann jemand erklären, welche Unterschiede bestehen und wie sie sich darauf auswirken, wie Code geschrieben wird?

Angesichts der Tatsache, dass die Dinge in Scala "einfach funktionieren", denke ich immer wieder, dass mir etwas an den in C # / Java (8) gewählten / vorgeschlagenen Ansätzen fehlt.

soc
quelle
1
Das ist interessant. Angesichts der Tatsache, dass das Javas-Typ-System derzeit kein Konzept für Funktionen hat, müsste dies zuerst eingeführt werden. Es könnte sein, dass die Sprache dabei zu komplex wird.
Ingo
Sind Funktionen nicht Instanzen irgendeiner Schnittstelle? Was ist das Besondere an ihnen?
Soc
Lisp / Scheme / Clojure kann Objekte modellieren, während Java / C # keine willkürliche Verschachtelung von Funktionen modellieren kann. Python scheint jedoch das Beste aus beiden Welten zu haben.
Job

Antworten:

15

Ich denke, die Diskussion zwischen Objekten und Funktionen ist ein roter Hering. Wenn die Frage lautet: "Ist ein Lambda eine Funktion oder ein Objekt?" Die Antwort sollte ja sein .

Darum geht es bei erstklassigen Funktionen: Sie werden nicht anders behandelt als jeder andere Typ. Java schafft es bereits, die Unterschiede zwischen Objekt- und primitiven Typen größtenteils zu ignorieren (und Scala noch besser). Ob also ein Lambda eine Unterklasse von Objekt oder ein neuer primitiver Typ ist oder etwas anderes, ist für die Sprache nicht wirklich wichtig. Wichtig ist, dass Sie Ihre Lambdas in Sammlungen ablegen, sie zum Aufrufen weitergeben, sie aufrufen und alles andere tun können, was Sie mit einem Objekt oder einer Methode tun möchten.

Scala erreicht dies durch die Verwendung eines Wrapper-Objekts mit einer aufgerufenen Methode, applydie mit just aufgerufen werden kann (), sodass es wie ein Methodenaufruf aussieht. Das funktioniert prächtig; Die meiste Zeit brauchen Sie sich nicht einmal darum zu kümmern, ob Sie eine Methode haben oder die Apply-Funktion eines Funktionsobjekts aufrufen.

Rex Kerr
quelle
9

Von dem, was ich verstehe, es ist mehr darüber , wie die Lambda - Ausdrücke sind als an dem primären Sprachniveau. Wie die E-Mail sagt,

Sie könnten denken, dass das aktuelle Design eng mit einer Objektbox für Lambdas - SAM-Typen - verknüpft ist, wodurch sie ohnehin effektiv zu Objekten werden. Dies wurde jedoch sorgfältig vor der Oberfläche verborgen, damit wir in Zukunft "nackte" Lambdas in Betracht ziehen oder andere Konvertierungskontexte für Lambdas in Betracht ziehen oder Lambdas enger in Kontrollkonstrukte integrieren können. Wir machen das jetzt nicht und haben noch nicht einmal einen konkreten Plan dafür, aber die Möglichkeit, dies möglicherweise in Zukunft zu tun, ist ein kritischer Teil des Designs.

Ich denke, das fasst deine Frage ganz gut zusammen. Wenn Sie erklären, dass "Lambdas Objekte sind", dann sind sie nur ein Objekt einer bestimmten Klasse und Sie stecken damit fest. Wenn Sie dagegen "Lambdas sind Funktionen" deklarieren, haben Sie semantisch ein viel besseres Spielfeld. Java 1.7 kompiliert sie möglicherweise zu Objekten, sodass sie zu diesem Zeitpunkt praktisch identisch sind.

Mit Java 1.8 oder 1.9 kann sich jedoch die Sprache ändern (z. B. umgestaltete Strukturtypen), sodass Funktionen wesentlich flexibler verwendet werden können. Wenn "Lambdas Objekte" wären, wären diese Änderungen nicht abwärtskompatibel, und Sie müssten ein neues Konzept einführen, um den vorhandenen Code der Leute nicht zu beschädigen. Aber wenn javacLambdas nur leise in Objekte hinter den Kulissen javackonvertiert werden, kann das neue Lambdas in beliebige konvertieren, solange die Semantik noch gültig ist.

Andrzej Doyle
quelle
Lamdas in C #! = von Delegierten. Der Compiler hat die Möglichkeit, sie entweder zu Delgates oder zu Expression-Bäumen zu kompilieren. beide sind zwar Objektgraphen, aber sie werden weder zu einer "bestimmten Klasse" noch zu einer Klasse eines bestimmten Erbbaums kompiliert
Rune FS
Wenn ich das richtig verstehe, wird das Lambda durch Kompilieren in eine innere Klasse des Objekts, mit dem es verknüpft ist, an dieses Objekt gebunden. Wenn Java also in Zukunft Funktionen höherer Ordnung (Funktionen auf derselben Objektebene) einführen würde, dann würden Sie Die Implementierung innerhalb der Klasse konnte nicht verwendet werden, und es würde eine Inkonsistenz geben. Ich glaube nicht, dass Java bald Funktionen höherer Ordnung haben wird.
Mwolfetech
@mwolfetech: Soweit ich weiß, sind sie bereits für Java 8 mit Defender-Methoden geplant. Sie wollen hinzufügen Dinge wie foreach, map, filterzu den Sammlungen.
soc
@soc Guter Punkt, es ist schwierig, mit der Anzahl der JSRs Schritt zu halten und festzustellen, ob sie tatsächlich eine Zielversion des JDK vervollständigen und erstellen werden. Es sieht so aus, als ob Verteidigermethoden Teil derselben JSR sein könnten. In Bezug auf diese JSR fand ich Brian Goetz ' Post über den Zustand des Lambda hilfreich - erläutert die SAM-Typen und die aktuellen Überlegungen zur Implementierung von Lambda-Ausdrücken.
Mwolfetech
"aktuelle gedanken" mhhh, ist dieser post von 2010 jetzt nicht obsolet?
Soc
5

Meistens will er sich einfach nicht zu früh auf etwas festlegen. Ich sehe keinen Grund, der über die von ihm vorgelegte Löschung hinausgeht, aber das ist in der Tat ein sehr starker Grund.

Ich mag keine Funktionstypen - ich liebe Funktionstypen - aber diese Funktionstypen haben schlecht mit einem existierenden Aspekt des Java-Typensystems, der Löschung, gekämpft. Gelöschte Funktionstypen sind die schlimmsten beider Welten.

Betrachten Sie diese Methoden in Scala Regex:

def replaceAllIn (target: CharSequence, replacer: (Match)  String): String
def replaceSomeIn (target: CharSequence, replacer: (Match)  Option[String]): String

Einfacher wäre es, wenn sie einfach so wären:

def replace (target: CharSequence, replacer: (Match)  String): String
def replace (target: CharSequence, replacer: (Match)  Option[String]): String

Dies ist leider nicht möglich, da diese beiden Funktionen beim Löschen identisch sind . Aber in Ordnung, diese Funktionen haben etwas anderes zu tun, so dass ein anderer Name durchaus gerechtfertigt ist.

Allerdings ist a Matchetwas sehr Nützliches, aber die meiste Zeit möchten Sie entweder die passende Stringoder die Liste der Untergruppen. Wir möchten folgendes haben:

def replaceAllIn (target: CharSequence, replacer: (String)  String): String
def replaceAllIn (target: CharSequence, replacer: (Seq[String])  String): String
def replaceAllIn (target: CharSequence, replacer: (Match)  String): String

Wegen Löschung nicht möglich. Ich habe mich für dieses Beispiel entschieden, weil ich direkt daran beteiligt war, aber ich habe mindestens ein halbes Dutzend Fragen zu Stack Overflow gesehen, in denen gefragt wurde, warum eine Überladung illegal ist, die durch genau dieses Problem verursacht wird.

Und dann bedenken Sie, dass Scalas Pattern Matching und Javas instanceofwegen Löschung praktisch unbrauchbar sind.

Ich halte es für angemessen, Funktionstypen zu verzögern, bis dieses Problem behoben ist. Immerhin gibt es in der JVM viele Sprachen, und Java ist keine sich schnell entwickelnde Sprache.

Daniel C. Sobral
quelle
Nun, wenn Typ-Löschung das einzige Problem ist, was planen sie dann zu tun? Alle Codes auf diesem Planeten zu brechen, war für Java 5 bereits eine
Nichtoption
@soc Ich bin so froh , dass ich nicht in ihren Schuhen bin! Aber das war Sun, das ist Oracle. Oracle hatte noch nie die Möglichkeit, Änderungen zwischen Haupt- und sogar Nebenversionen seines Hauptprodukts vorzunehmen.
Daniel C. Sobral
Vielleicht sollten sie den Namen der Sprache ändern und anfangen, eine neue Sprache zu entwickeln, wodurch die Abwärtskompatibilität verloren geht. Man hätte also die Vorteile einer neuen Sprache, ohne mit einer älteren und etablierten Sprache herumspielen zu müssen. Immerhin haben Scala und Clojure das getan.
Giorgio
@Giorgio Das wäre ein bisschen sinnlos. Nun, einige der Leute, die für das verantwortlich sind, was Java heute ist, haben das getan, aber wie Sie sagten, gibt es Alternativen. Aber die Verantwortlichen für Java müssen Java selbst verbessern - sie sind schließlich dafür verantwortlich . Die einzige Alternative besteht darin, Java einfach fallen zu lassen und auf alle Vorteile zu verzichten, die sich aus seiner Steuerung ergeben.
Daniel C. Sobral
@Daniel C. Sobral: IMO eine Programmiersprache ist ein bisschen wie ein Stück Software: Am Anfang kann es sauber und gut gestaltet sein, aber je mehr Sie damit spielen, desto mehr wird es chaotisch. Ich denke, es wäre im Interesse der Entwickler, Java als Sprache einzufrieren und die Entwicklung darauf zu konzentrieren, (1) neue Bibliotheken zu erstellen oder bestehende zu verbessern, (2) die JVM zu verbessern (wenn möglich), (3) neue Sprachen zu entwickeln . Aber wie Sie sagten, gibt es Leute, die für Java verantwortlich sind und weiterhin Upgrades verkaufen möchten. Also werden sie es erweitern, um es "cool" zu halten. Nur meine 2 Cent.
Giorgio