Call-by-Value vs. Call-by-Name in Scala
- Call-by-Value in Scala
- Anruf nach Name in Scala
- Call-by-Value- vs. Call-by-Name-Strategien in Scala
- Abschluss
In diesem Artikel lernen wir die Call-by-Value- und Call-by-Name-Funktionen und deren Bewertungsstrategien in Scala kennen. Und wir werden diskutieren, wie man sie in der Praxis einsetzt.
Call-by-Value in Scala
Funktionsargumente in Scala werden standardmäßig als Call-by-Value betrachtet. Sehen wir uns ein kleines Beispiel an:
def example(x:Int) = x*x
Im obigen Code haben wir eine Funktion Beispiel
definiert, die ein Argument als Call-by-Value akzeptiert.
Im Allgemeinen werden parametrisierte Funktionen, genau wie Operatoren in Scala, vom Compiler auf die gleiche Weise ausgewertet. Zunächst werden alle Funktionsargumente von links nach rechts ausgewertet; dann werden alle Funktionsanwendungen durch die rechte Seite der Funktion ersetzt.
Gleichzeitig werden alle formalen Parameter der Funktion durch die eigentlichen Parameter ersetzt.
Ein großer Vorteil der Call-by-Value-Strategie ist, dass jedes Funktionsargument nur einmal ausgewertet wird.
Anruf nach Name in Scala
Wir stellen den Funktionsargumenten nur =>
(gleich und größer als Symbol) voran, um den Argumentaufruf nach Namen durchzuführen.
Sehen wir uns ein kleines Beispiel an, um es besser zu verstehen:
def example(x: =>Int) = x*x
Der Parameter x
im obigen Code wird nach Wert aufgerufen. Obwohl die Call-by-Name-Evaluierung mit der Call-by-Value-Strategie identisch ist, hat sie einen großen Vorteil: Die Funktion wird erst ausgewertet, wenn ihr entsprechender Wert im Funktionskörper verwendet wird.
Call-by-Value- vs. Call-by-Name-Strategien in Scala
Nehmen wir an, wir haben eine Funktion add
mit zwei Parametern: x
, die vom Typ int ist und nach Wert aufgerufen wird, und y
, die vom Typ int ist und nach Name aufgerufen wird.
def add(x: Int, y:=>Int) = x+x
Sehen wir uns an, wie die Funktion add
mit der Call-by-Value-Strategie ausgewertet wird.
assert(add(3+3,8) == 12)
Hier wertet der Call-by-Value zuerst den Ausdruck 3+3
aus und übergibt dann den Wert 6
an den Rumpf der Funktion. Der Parameter x
wird zu sich selbst addiert, um die endgültige Antwort als 12
zu berechnen.
Sehen wir uns nun dieselbe Funktion an, die mit der Call-by-Name-Strategie ausgewertet wird.
assert(add(8,3+3) == 16)
In diesem Fall wird 3+3
von der Call-by-Name-Strategie ignoriert, da der Parameter y
niemals innerhalb des Funktionskörpers verwendet wird. Daher wird das x
zu sich selbst addiert, um die endgültige Antwort als 16
zu berechnen.
Wir können sagen, dass die Call-by-Name-Strategie in diesem Fall etwas schneller ist als die Call-by-Value-Strategie.
Sehen wir uns noch ein Beispiel an, wo wir eine Funktion haben, die sich selbst unendlich rekursiv aufruft.
def myFun(): Int = myFun() + 1
Wenn wir nun diese Funktion als Parameter x
in unserer add
-Funktion verwenden, dann ergibt das call by value
-Argument x
StackOverflowError
.
assertThrows[StackOverflowError]
{
add(myFun(),5)
}
Im obigen Code gibt der Aufruf der Funktion StackOverflowError
zurück, da die Methode myFun()
vor ihrem Funktionsrumpf ausgewertet wird. Wenn wir dagegen die Methode myFun
als Call-by-Name-Argument verwenden, wird der Funktionsaufruf erfolgreich ausgeführt, ohne dass eine Ausnahme ausgelöst wird, da er niemals innerhalb des Funktionskörpers ausgewertet wird.
assert(add(5, myFun()) == 10)
die bessere in unserem Kodex zu verwenden
Basierend auf den obigen Beispielen scheint die Call-by-Name-Strategie ansprechender zu sein, da sie effizienter ist, da die Möglichkeit besteht, dass das übergebene Argument niemals innerhalb des Funktionskörpers ausgewertet wird.
Ganzheitlich gesehen ist die Call-by-Value-Strategie jedoch effizienter als die Call-by-Name-Strategie, da darin das wiederholte Rechnen von Argumenten vermieden wird. Außerdem können die Seiteneffekte vermieden werden, da wir wissen, wann die Argumente im Code ausgewertet werden.
Abschluss
In diesem Artikel haben wir die Call-by-Name- und Call-by-Value-Strategien von Scala kennengelernt. Wir haben gelernt, wie sie bewertet werden, und ihre Verwendung gesehen, und sind zu dem Schluss gekommen, dass die Call-by-Value-Strategie in den meisten Fällen besser zu verwenden ist.