- About Scala
- Documentation
- Code Examples
- Software
- Scala Developers
Compiler bug with -optimise and final classes with var constructors
Fri, 2009-08-21, 22:27
The following program gives incorrect results when compiled with the -optimise flag under 2.7.4, 2.7.5, and last night's nightly build of 2.8.0:
Code:
final class V(var x:Int , var y:Int) {
def +=(ax:Int,ay:Int) { x += ax ; y += ay }
}
final class U {
var x:Int = 0
var y:Int = 0
def +=(ax:Int,ay:Int) { x += ax ; y += ay }
}
object Fail {
def main(args:Array[String]) {
val vm = new V(0,0)
vm += (5,10)
val um = new U
um += (5,10)
var i = 0
while (i<1) {
um += ( i , 1-i )
i += 1
}
println("Answers are " + (vm.x+vm.y) + " and " + (um.x+um.y))
}
}
Good output:
~/code/scala$ rm *.class ; ~/pkg/scala-2.8.0.r18509-b20090819020207/bin/scalac Fail.scala
~/code/scala$ java -cp ~/pkg/scala-2.8.0.r18509-b20090819020207/lib/scala-library.jar:. Fail
Answers are 15 and 16
~/code/scala$
Bad optimized output:
~/code/scala$ rm *.class ; ~/pkg/scala-2.8.0.r18509-b20090819020207/bin/scalac -optimise Fail.scala
~/code/scala$ java -cp ~/pkg/scala-2.8.0.r18509-b20090819020207/lib/scala-library.jar:. Fail
Answers are 0 and 16
~/code/scala$
Somehow, even though um of type U is being operated on in the loop, it wipes out the value in vm.
Removing the loop fixes the problem. Having V non-final fixes the problem. Moving the vars inside the body of the class fixes the problem (as U demonstrates). Making vm a var does *not* fix the problem. Making vm a tuple with the vector as vm._1 fixes the problem. Putting vm into another tuple right after vm += (5,10) fixes the problem *if* you read from the tuple for the answer, but *not* if you read from vm itself for the answer. Simply setting another val equal to vm (i.e. creating a reference) does not fix the problem. In more complicated programs, this bug can manifest intermittently--multiple compiles of the same code will sometimes show this bug and sometimes not.
Has anyone else noticed anything like this? I suppose the proper thing to do is to submit this to the ScalaTrac database.
--Rex
Code:
final class V(var x:Int , var y:Int) {
def +=(ax:Int,ay:Int) { x += ax ; y += ay }
}
final class U {
var x:Int = 0
var y:Int = 0
def +=(ax:Int,ay:Int) { x += ax ; y += ay }
}
object Fail {
def main(args:Array[String]) {
val vm = new V(0,0)
vm += (5,10)
val um = new U
um += (5,10)
var i = 0
while (i<1) {
um += ( i , 1-i )
i += 1
}
println("Answers are " + (vm.x+vm.y) + " and " + (um.x+um.y))
}
}
Good output:
~/code/scala$ rm *.class ; ~/pkg/scala-2.8.0.r18509-b20090819020207/bin/scalac Fail.scala
~/code/scala$ java -cp ~/pkg/scala-2.8.0.r18509-b20090819020207/lib/scala-library.jar:. Fail
Answers are 15 and 16
~/code/scala$
Bad optimized output:
~/code/scala$ rm *.class ; ~/pkg/scala-2.8.0.r18509-b20090819020207/bin/scalac -optimise Fail.scala
~/code/scala$ java -cp ~/pkg/scala-2.8.0.r18509-b20090819020207/lib/scala-library.jar:. Fail
Answers are 0 and 16
~/code/scala$
Somehow, even though um of type U is being operated on in the loop, it wipes out the value in vm.
Removing the loop fixes the problem. Having V non-final fixes the problem. Moving the vars inside the body of the class fixes the problem (as U demonstrates). Making vm a var does *not* fix the problem. Making vm a tuple with the vector as vm._1 fixes the problem. Putting vm into another tuple right after vm += (5,10) fixes the problem *if* you read from the tuple for the answer, but *not* if you read from vm itself for the answer. Simply setting another val equal to vm (i.e. creating a reference) does not fix the problem. In more complicated programs, this bug can manifest intermittently--multiple compiles of the same code will sometimes show this bug and sometimes not.
Has anyone else noticed anything like this? I suppose the proper thing to do is to submit this to the ScalaTrac database.
--Rex