Skip to content

Instantly share code, notes, and snippets.

@gseitz
Created October 14, 2013 15:06
Show Gist options
  • Save gseitz/6977143 to your computer and use it in GitHub Desktop.
Save gseitz/6977143 to your computer and use it in GitHub Desktop.
AbstractMethodError at runtime
package com.leonteq.datahubconnector.util
object FooImpl extends GoodBar[Int]
object BadFooImpl extends BadFoo with BadBar[Int]
trait BadFoo {
this: BadBar[_] =>
def mapBazes = bazes.map(identity)
}
trait BadBar[A] {
type Baz[B] = Option[A] // notice the reference to A
def bazes: Seq[Baz[_]] = List[Baz[_]](None)
}
trait GoodBar[A] {
type Baz[B] = Option[B]
def bazes: Seq[Baz[_]] = List[Baz[_]](None)
}
object Test extends App {
// this works
println(FooImpl.bazes.map(identity))
println(BadFooImpl.bazes.map(identity))
// this doesn't
println(BadFooImpl.mapBazes)
// java.lang.AbstractMethodError
// at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:244)
// at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:244)
// at scala.collection.immutable.List.foreach(List.scala:318)
// at scala.collection.TraversableLike$class.map(TraversableLike.scala:244)
// at scala.collection.AbstractTraversable.map(Traversable.scala:105)
}
package com.leonteq.datahubconnector.util
trait GoodFoo {
this: Bar[_] with GoodBar[_] =>
def mapBazes = bazes.map(identity)
}
trait AlsoGoodFoo {
this: Bar[_] =>
def mapBazes = bazes.map(identity)
}
trait BadFoo {
this: Bar[_] with BadBar[_] =>
// BadFoo wants to know about the specific type BadBar[_]#Baz
def mapBazes = bazes.map(_.isDefined)
}
trait BadBar[A] extends Bar[A] {
type Baz[B] = Option[A]
def bazes: Seq[Baz[_]] = List[Baz[_]](None)
}
trait GoodBar[A] extends Bar[A] {
type Baz[B] = Option[B]
def bazes: Seq[Baz[_]] = List[Baz[_]](None)
}
trait Bar[A] {
type Baz[B]
def bazes: Seq[Baz[_]]
}
object GoodFooImpl extends GoodFoo with GoodBar[Int]
object AlsoGoodFooImpl extends AlsoGoodFoo with GoodBar[Int]
object BadFooImpl extends BadFoo with BadBar[Int]
object Test extends App {
// this works
println(GoodFooImpl.mapBazes)
println(AlsoGoodFooImpl.mapBazes)
// this doesn't
println(BadFooImpl.bazes.map(_.isDefined))
println(BadFooImpl.bazes.map(identity))
println(BadFooImpl.mapBazes)
// java.lang.AbstractMethodError
// at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:244)
// at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:244)
// at scala.collection.immutable.List.foreach(List.scala:318)
// at scala.collection.TraversableLike$class.map(TraversableLike.scala:244)
// at scala.collection.AbstractTraversable.map(Traversable.scala:105)
}
@gseitz
Copy link
Author

gseitz commented Oct 14, 2013

@retronym: We ran into this situation last week. Minified.scala shows a minimum version of the bug, whereas MotivatingExample.scala should show why you want this in the first place.

Everything compiles fine, but calling BadFooImpl.mapBazes yields an AbstractMethodError at runtime.

The actual piece of code is trying to separate a TableModel/TableColumn with the accompanying CellRenderers, while retaining relative type safety between various incarnations of these (eg. ExcelCellRenderer, HtmlCellRenderer).

I did a quick search in JIRA, but nothing really similar showed up.

The obvious workaround is to add a type parameter to BadFoo and pass that on to Bar and BadBar, but I would have rather expected a compiler error, if it's indeed erroneous code.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment