Подтвердить что ты не робот

Почему Scala оценивает аргумент для параметра по умолчанию, если метод является инфиксным и право-ассоциативным?

Как я понял параметры call-by-name метода, соответствующее выражение аргумента не будет оцениваться при передаче его методу, но только тогда, когда (и if) значение параметра используется в теле метода.

В следующем примере, однако, это верно только в первых двух вызовах метода, но не в третьем, хотя это должно быть просто синтаксическим изменением второго случая!?

Почему выражение аргумента, оцененное при вызове третьего метода?

(я тестировал этот код с помощью Scala 2.11.7)

class Node(x: => Int)

class Foo {
  def :: (x: =>Int) = new Node(x)  // a right-associative method
  def !! (x: =>Int) = new Node(x)  // a left-associative method
}

// Infix method call will not evaluate a call-by-name parameter:
val node = (new Foo) !! {println(1); 1}
println("Nothing evaluated up to here")

// Right-associative method call will not evaluate a call-by-name parameter:
val node1 = (new Foo).::({println(1); 1})
println("Nothing evaluated up to here")

// Infix and right-associative method call will evaluate a call-by-name parameter - why??
val node2 = {println(1); 1} ::(new Foo)  // prints 1
println("1 has been evaluated now - why??")
4b9b3361

Ответ 1

Аргументы по-имени оцениваются всякий раз, когда они упоминаются. Спектр говорит, что вызовы метода право-ассоциативного оператора оцениваются следующим образом:

a op_: b

desugars:

{ val someFreshName = a; b.op_:(someFreshName) }
//                   ↑↑↑
// Eval happens here ↑↑↑

Ответ 2

Это ошибка. Старый, при этом.

См. SI-1980 и PR # 2852.

Связанный запрос тяги добавил предупреждение компилятора при использовании флага -Xlint:

<console>:13: warning: by-name parameters will be evaluated eagerly when called as a right-associative infix operator. For more details, see SI-1980.
         def :: (x: =>Int) = new Node(x)  // a right-associative method
             ^