I want different method binding (at compile-time !) depending on a marker trait (like Cream). How can this be achieved ?
My solution below does not compile.
How can it be fixed ?
class Apple
class Banana
trait Cream
object HasOverloadedMethods
{
def method(p:Apple)=println("Apple")
def method(p:Banana)=println("Banana")
def method(p:Banana with Cream)=println("Banana with Cream")
}
object Question extends App{
HasOverloadedMethods.method(new Apple())
HasOverloadedMethods.method(new Banana())
HasOverloadedMethods.method(new Banana() with Cream)
}
error:
double definition:
method method:(p: Banana with Cream)Unit and
method method:(p: Banana)Unit at line 9
have same type after erasure: (p: Banana)Unit
def method(p:Banana with Cream)=println("Banana with Cream")
^
Unfortunately you can't fix it like that, since the JVM doesn't know mixin types (and the bytecode signature of method(x: Banana with Cream) is therefore only method(x: Banana)).
You have a couple of options, which all have their drawbacks.
Cream. This makes you loose the BananaBananaWithCream trait. This clutters your hierarchy.Use type-classes:
def method[T : MethImpl](x: T) = implicitly[MethImpl[T]].impl(x)
trait MethImpl[T] {
def impl(x: T): Unit
}
trait LowPrioMethImpl {
implicit object BananaImpl extends MethImpl[Banana] {
def impl(x: Banana) = println("Banana")
}
}
object MethImpl extends LowPrioMethImpl {
implicit object AppleImpl extends MethImpl[Apple] {
def impl(x: Apple) = println("Apple")
}
implicit object BananaWithCreamImpl extends MethImpl[Banana with Cream] {
def impl(x: Banana with Cream) = println("Banana with Cream")
}
}
Now you can:
method(new Banana) // > Banana
method(new Banana with Cream) // > Banana with Cream
method(new Apple) // > Apple
method("adsf") // error: Could not find implicit value ...
The con is obviously the clutter this solution introduces.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With