bug icon indicating copy to clipboard operation
bug copied to clipboard

problem with super in traits in case when build-in java.lang.Object methods was "maliciously" made abstract

Open ibaklan opened this issue 6 years ago • 4 comments

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 class SuppressToString where toString 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)

ibaklan avatar Aug 14 '18 11:08 ibaklan

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.

Blaisorblade avatar Aug 14 '18 17:08 Blaisorblade

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.

som-snytt avatar Dec 13 '19 18:12 som-snytt

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.

Blaisorblade avatar Dec 15 '19 10:12 Blaisorblade

Yes, spec 5.1.3 definition of abstract member. So it's not override but membership.

som-snytt avatar Dec 15 '19 16:12 som-snytt