Call-by-Value vs. Call-by-Name in Scala

Suraj P 21 Juni 2023
  1. Call-by-Value in Scala
  2. Anruf nach Name in Scala
  3. Call-by-Value- vs. Call-by-Name-Strategien in Scala
  4. Abschluss
Call-by-Value vs. Call-by-Name in Scala

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.

Autor: Suraj P
Suraj P avatar Suraj P avatar

A technophile and a Big Data developer by passion. Loves developing advance C++ and Java applications in free time works as SME at Chegg where I help students with there doubts and assignments in the field of Computer Science.

LinkedIn GitHub

Verwandter Artikel - Scala Function