Was ist die Motivation für die Bewertung der Scala-Zuordnung zur Einheit und nicht für den zugewiesenen Wert?
Ein gängiges Muster bei der E / A-Programmierung ist Folgendes:
while ((bytesRead = in.read(buffer)) != -1) { ...
Dies ist in Scala jedoch nicht möglich, weil ...
bytesRead = in.read(buffer)
.. gibt Unit zurück, nicht den neuen Wert von bytesRead.
Es scheint interessant zu sein, eine funktionale Sprache wegzulassen. Ich frage mich, warum es so gemacht wurde?
scala
functional-programming
io
assignment-operator
Graham Lea
quelle
quelle
Antworten:
Ich habe mich dafür eingesetzt, dass Zuweisungen den zugewiesenen Wert und nicht die Einheit zurückgeben. Martin und ich gingen hin und her, aber sein Argument war, dass es eine Verschwendung von Byte-Codes ist, einen Wert auf den Stapel zu setzen, um ihn zu 95% der Zeit zu entfernen, und sich negativ auf die Leistung auswirkt.
quelle
void
. In Scalafoo_=(v: Foo)
sollte zurückkehren,Foo
wenn die Zuordnung dies tut.void
(Unit
), Zuweisungenx = value
werden in Äquivalente von übersetztx.set(value);x.get(value)
; Der Compiler eliminiert in Optimierungsphasen dieget
Aufrufe, wenn der Wert nicht verwendet wurde. Es könnte eine willkommene Änderung in einer neuen Hauptversion von Scala (aufgrund von Abwärtsinkompatibilität) und weniger Irritationen für Benutzer sein. Was denken Sie?Ich bin nicht mit Insiderinformationen über die tatsächlichen Gründe vertraut, aber mein Verdacht ist sehr einfach. Scala macht die Verwendung von Nebenwirkungsschleifen umständlich, so dass Programmierer natürlich das Verständnis bevorzugen.
Dies geschieht auf viele Arten. Zum Beispiel haben Sie keine
for
Schleife, in der Sie eine Variable deklarieren und mutieren. Sie können den Status eines (nicht einfach) mutierenwhile
Schleife gleichzeitig mit dem Testen der Bedingung bedeutet, dass Sie die Mutation häufig unmittelbar vor und am Ende wiederholen müssen. In einemwhile
Block deklarierte Variablen sind in derwhile
Testbedingung nicht sichtbar , wasdo { ... } while (...)
viel weniger nützlich ist. Und so weiter.Problemumgehung:
Für was auch immer es wert ist.
Als alternative Erklärung musste sich Martin Odersky vielleicht einigen sehr hässlichen Fehlern stellen, die sich aus einer solchen Verwendung ergaben, und beschloss, sie aus seiner Sprache zu verbannen.
BEARBEITEN
David Pollack hat geantwortet mit einigen tatsächlichen Fakten , die eindeutig durch die Tatsache bestätigt werden, dass Martin Odersky selbst seine Antwort kommentierte und dem von Pollack vorgebrachten Argument der leistungsbezogenen Fragen Glauben schenkt.
quelle
for
Loop-Version also: Dasfor (bytesRead <- in.read(buffer) if (bytesRead) != -1
ist großartig, außer dass es nicht funktioniert, weil es keine gibtforeach
undwithFilter
verfügbar ist!Dies geschah als Teil von Scala mit einem "formal korrekteren" Typsystem. Formal gesehen ist die Zuweisung eine rein nebensächliche Aussage und sollte daher zurückkehren
Unit
. Dies hat einige nette Konsequenzen; beispielsweise:Die
state_=
Methode gibtUnit
(wie für einen Setter zu erwarten) genau deshalb zurück, weil die Zuweisung zurückkehrtUnit
.Ich bin damit einverstanden, dass für C-Muster wie das Kopieren eines Streams oder ähnliches diese spezielle Entwurfsentscheidung etwas mühsam sein kann. Es ist jedoch im Allgemeinen relativ unproblematisch und trägt wirklich zur Gesamtkonsistenz des Typsystems bei.
quelle
Vielleicht liegt das am Prinzip der Befehl-Abfrage-Trennung ?
CQS ist in der Regel an der Schnittstelle von OO- und funktionalen Programmierstilen beliebt, da es eine offensichtliche Unterscheidung zwischen Objektmethoden schafft, die Nebenwirkungen haben oder nicht (dh das Objekt verändern). Das Anwenden von CQS auf Variablenzuweisungen geht weiter als gewöhnlich, aber die gleiche Idee gilt.
Eine kurze Darstellung von warum CQS ist nützlich: eine hypothetische Hybrid - F / OO - Sprache mit einer Betrachten
List
Klasse , die Methoden hatSort
,Append
,First
, undLength
. Im imperativen OO-Stil möchte man möglicherweise eine Funktion wie die folgende schreiben:Während man in einem funktionaleren Stil eher so etwas schreiben würde:
Diese scheinen es zu versuchen , dasselbe zu tun, aber offensichtlich ist eine der beiden falsch, und ohne mehr über das Verhalten der Methoden zu wissen, können wir nicht sagen, welche.
Bei Verwendung von CQS würden wir jedoch darauf bestehen, dass wenn
Append
undSort
die Liste ändern, müssen sie den Einheitentyp zurückgeben, damit wir verhindern , dass Fehler zu schaffen , indem die zweite Form zu verwenden , wenn wir nicht sollten. Das Vorhandensein von Nebenwirkungen wird daher auch in der Methodensignatur impliziert.quelle
Ich würde vermuten, dass dies dazu dient, das Programm / die Sprache frei von Nebenwirkungen zu halten.
Was Sie beschreiben, ist die absichtliche Verwendung einer Nebenwirkung, die im allgemeinen Fall als eine schlechte Sache angesehen wird.
quelle
val a = b = 1
(man stelle sich „magische“val
vorb
) vs.val a = 1; val b = 1;
.Es ist nicht der beste Stil, eine Zuweisung als booleschen Ausdruck zu verwenden. Sie führen zwei Dinge gleichzeitig aus, was häufig zu Fehlern führt. Und die versehentliche Verwendung von "=" anstelle von "==" wird mit der Einschränkung von Scalas vermieden.
quelle
Übrigens: Ich finde den anfänglichen While-Trick auch in Java dumm. Warum nicht so etwas?
Zugegeben, die Zuweisung wird zweimal angezeigt, aber zumindest bytesRead befindet sich in dem Bereich, zu dem sie gehört, und ich spiele nicht mit lustigen Zuweisungstricks ...
quelle
Sie können eine Problemumgehung dafür haben, solange Sie einen Referenztyp für die Indirektion haben. In einer naiven Implementierung können Sie Folgendes für beliebige Typen verwenden.
Anschließend können Sie unter der Einschränkung, die Sie verwenden müssen, um anschließend
ref.value
auf die Referenz zuzugreifen, Ihrwhile
Prädikat als schreibenund Sie können die Prüfung
bytesRead
impliziter durchführen, ohne sie eingeben zu müssen.quelle