问题
From book 'Programming in Scala':
var assertionsEnabled = true
def myAssert(predicate: () => Boolean) =
if (assertionsEnabled && !predicate())
throw new AssertionError
myAssert(() => 5 > 3)
Using empty parameter list is awkward. Scala provides by-name parameter to solve this.
def byNameAssert(predicate: => Boolean) =
if (assertionsEnabled && !predicate)
throw new AssertionError
byNameAssert(5 > 3)
I have a confusion in this discussion.myAssert takes in a parameter which is a function, which in turn takes no parameter and returns a boolean.
What is input type for byNameAssert?Is it same as myAssert?To me,it seems an expression which evaluates to a boolean value, and having it in by-name form means that expression is evaluated whenever it is called and not when being passed to byNameAssert.But then it is not same as input type of myAssert. And if that is the case, then byNameAssert and myAssert are quite different.
回答1:
To me,it seems an expression which evaluates to a boolean value, and having it in by-name form means that expression is evaluated whenever it is called and not when being passed to byNameAssert.
Yes. But the way it's implemented is that Scala compiles byNameAssert
and myAssert
to exactly the same code (except for different @ScalaSignature
annotation) and whenever it sees calls like byNameAssert(5 > 3)
they are rewritten so the next compiler stage sees the argument as () => 5 > 3
instead.
回答2:
What is input type for byNameAssert?
=> Boolean
Is it same as myAssert?
No, myAssert
expects () => Boolean
as argument. While "morally the same", it is treated as a separate type by the compiler.
The => Boolean
-thing is neither () => Boolean
, nor Boolean
. The following little example is supposed to further illustrate that. Trying to assign curried foo
to variables of type () => Boolean
and Boolean
fails:
scala> def foo(b: => Boolean): Unit = {}
foo: (b: => Boolean)Unit
scala> val f: Boolean => Unit = foo _
<console>:12: error: type mismatch;
found : (=> Boolean) => Unit
required: Boolean => Unit
val f: Boolean => Unit = foo _
^
scala> val f: (() => Boolean) => Unit = foo _
<console>:12: error: type mismatch;
found : (=> Boolean) => Unit
required: (() => Boolean) => Unit
val f: (() => Boolean) => Unit = foo _
^
But this works:
scala> val f: (=> Boolean) => Unit = foo _
f: (=> Boolean) => Unit = $$Lambda$1090/668948486@69bc9584
So, while => Boolean
is essentially the same as () => Boolean
from the point of view of the implementation, it is treated separately as a different type, and it behaves quite differently when it comes to syntactic desugaring of expressions and code blocks passed as arguments to functions.
来源:https://stackoverflow.com/questions/49707521/by-name-parameter-in-scala