By-name parameter in Scala

China☆狼群 提交于 2019-12-11 15:52:44

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!