-
Notifications
You must be signed in to change notification settings - Fork 21
Overly-Eager Evaluation of By-Name Parameter in Inferred Partial Application #5610
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Imported From: https://issues.scala-lang.org/browse/SI-5610?orig=1 |
@odersky said: |
@retronym said: object Bug {
def main(args: Array[String]) {
var test: String = null
val result = bar(foo(test))
test = "bar"
if (result.str == null) {
println("Destroy ALL THE THINGS!!!")
} else {
println("Stroke a kitten")
}
}
class Result(_str: => String) {
lazy val str = _str
}
def foo(str: => String)(i: Int) = new Result(str)
def bar(f: Int => Result) = f(42)
} |
@lrytz said (edited on May 13, 2012 9:56:32 AM UTC): object Bug {
def main(args: Array[String]): Unit = {
var test: String = null
val fun1: Int => () => Unit = foo(test) _
val fun2: Int => () => Unit = foo(test)(_)
test = "some string"
fun1(1)()
fun2(1)()
}
def foo(s: => String)(dummy: Int) = () => println(s)
} This prints null
some string because the two functions val fun1: Int => (() => Unit) = {
<synthetic> val eta$0$1: String = test;
((dummy: Int) => Bug.this.foo(eta$0$1)(dummy))
};
val fun2: Int => (() => Unit) = ((x$1: Int) => Bug.this.foo(test)(x$1)); I guess the synthetic value should be lazy. |
@lrytz said: However, this issue is blocked by #5796. Another option is to use a val fun1: Int => (() => Unit) = {
<synthetic> val eta$0$1: () => String = () => test; // Create Function0 value
((dummy: Int) => Bug.this.foo(eta$0$1())(dummy)) // Apply the function here
};
val fun2: Int => (() => Unit) = ((x$1: Int) => Bug.this.foo(test)(x$1)); This is what is currently done for named arguments, i.e. given {
val x$1: () => Int = () => expr
val x$2: Int = 1
f(x$2, x$1)
} |
@lrytz said: |
@lrytz said: |
Robert Gibson (rgibson) said: |
@lrytz said: |
@som-snytt said: |
@SethTisue said: (is it because the spec change is still pending?) |
We would expect the output of this code would be "Stroke a kitten", since the value of
test
is given a non-null value before thestr
lazy val is realized. However, the actual printout is "Destroy ALL THE THINGS!!!", which isn't a polite thing to do.The problem lies in the bytecode generated for
bar(foo(test))
. More specifically, the issue is in the lifting of thetest
actual for thefoo
invocation. Bytecode (from Bug$delayedInit$body.apply:()Ljava/lang/Object;):Notice instruction 22. We're getting a raw (un-thunked) value for
test
and then lifting it into the requisite closure for the foo(test) invocation.Using an explicit thunk (of type () => String) rather than a by-name parameter for
str
avoids this issue.The text was updated successfully, but these errors were encountered: