bug
bug copied to clipboard
problem with super in traits in case when build-in java.lang.Object methods was "maliciously" made abstract
Consider following code
package crafts
object Main {
def main(args: Array[String]): Unit = {
val obj = new Combined
println(s"obj: ${obj}")
}
class Combined extends SuppressToString with WrapToString
abstract class SuppressToString {
override def toString: String
}
trait WrapToString {
override def toString: String = "WrapToString: " + super.toString
}
}
- Expected result: should fail on compile time since
WrapToString
trait can not be mixed with classSuppressToString
wheretoString
method is abstract - Actual result: code compiles successfully and then predictably fails on runtime with the following error
Exception in thread "main" java.lang.AbstractMethodError: java.lang.Object.toString()Ljava/lang/String;
at crafts.Main$Combined.crafts$Main$WrapToString$$super$toString(Main.scala:10)
at crafts.Main$WrapToString.toString(Main.scala:17)
at crafts.Main$WrapToString.toString$(Main.scala:17)
at crafts.Main$Combined.toString(Main.scala:10)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at crafts.Main$.main(Main.scala:7)
at crafts.Main.main(Main.scala)
(related discussion added)
The compiler clearly shouldn't crash here, it should either fail to compile or consider the method as already implemented (which it is); removing toString
is not a supported use case. Sadly, this crashes in Dotty too.
Clarification per previous comment, it's a runtime error, not a compiler crash.
In Scala 2, a concrete member always overrides an abstract member, irregardless [sic] of linearization. I wonder if this bug is a "defined in Java" thing or a "defined in Any" thing or just a bug.
I’ve posted further analysis on the Dotty bugtracker, including the output (of either Scalac or Dotty): https://github.com/lampepfl/dotty/issues/4943#issuecomment-412962754
In Scala 2, a concrete member always overrides an abstract member, irregardless [sic] of linearization.
Is that the spec? Because it doesn’t seem to be what happens there. In particular, the JVM seems to allow overriding a concrete method with an abstract method, making Any.toString impossible to call.
Yes, spec 5.1.3 definition of abstract member. So it's not override but membership.