L'exemple que vous avez donné utilise uniquement l'appel par valeur, je vais donc donner un nouvel exemple, plus simple, qui montre la différence.
Tout d'abord, supposons que nous avons une fonction avec un effet secondaire. Cette fonction imprime quelque chose et renvoie un Int
.
def something() = {
println("calling something")
1 // return value
}
Maintenant, nous allons définir deux fonctions qui acceptent Int
qui sont exactement les mêmes, sauf que l'un d'entre eux prend l'argument dans un style appel par valeur ( x: Int
) et l'autre dans un style "appel par nom" ( x: => Int
).
def callByValue(x: Int) = {
println("x1=" + x)
println("x2=" + x)
}
def callByName(x: => Int) = {
println("x1=" + x)
println("x2=" + x)
}
Maintenant, que se passe-t-il lorsque nous les appelons avec notre fonction à effet secondaire ?
scala> callByValue(something())
calling something
x1=1
x2=1
scala> callByName(something())
calling something
x1=1
calling something
x2=1
Vous pouvez donc voir que dans la version "call-by-value", l'effet secondaire de l'appel de fonction transmis ( something()
) ne s'est produit qu'une seule fois. Cependant, dans la version call-by-name, l'effet secondaire se produit deux fois.
Cela est dû au fait que les fonctions call-by-value calculent la valeur de l'expression passée avant d'appeler la fonction, ce qui fait que la fonction même est accessible à chaque fois. Au lieu de cela, les fonctions d'appel par nom recalculer la valeur de l'expression transmise à chaque fois qu'on y accède.