Say I have two sets of classes and the first set inherits from Foo and the second set inherits from Bar.
class Foo
class Baz extends Foo
class Bar
class Qux extends Bar
I want to make a generic implicit conversion function that converts any Foo to Bar given there is an implicit converter type in scope.
trait Converter[A <: Foo, B <: Bar] {
def convert(a : A) : B
}
implicit object BazToQuxConverter extends Converter[Baz, Qux] {
def convert(a : Baz) : Qux = new Qux
}
implicit def FooToBar[A <: Foo, B <: Bar](a : A)(implicit converter : Converter[A, B]) : B = converter.convert(a)
Unfortunately, this doesn't seem to work as I would expect it to. When I plug in the following lines to the REPL:
val a : Baz = new Baz
val b : Qux = a
...I get the following error:
<console>:17: error: type mismatch;
found : Baz
required: Qux
val b : Qux = a
^
Is there any way to get this to work? The closest I've been able to come is the following:
implicit def BadFooToBar[A <: Foo, B <: Bar](a : A)(implicit converter : Converter[A, _]) : B = converter.convert(a).asInstanceOf[B]
This does work for my previous example, but it's not very type-safe.
class Qax extends Bar
val a : Baz = new Baz
val b : Qax = a
This will compile just fine, but it will blow up at run-time because a Qux
(the result of converter.convert(a)
) can't be cast to Qax
(asInstanceOf[Qax]
). Ideally, I want it so that the above line will be caught at compile time since there isn't any Converter[Bax,Qax]
in scope.
This is a bug which is fixed in 2.11. It looks like it has been fixed since PR 2822, the related ticket is SI-3346.
Welcome to Scala version 2.11.0-20131030-090728-c38235fd44 (OpenJDK 64-Bit Server VM, Java 1.7.0_45).
Type in expressions to have them evaluated.
Type :help for more information.
scala> :paste
// Entering paste mode (ctrl-D to finish)
class Foo
class Baz extends Foo
class Bar
class Qux extends Bar
trait Converter[A <: Foo, B <: Bar] {
def convert(a : A) : B
}
implicit object BazToQuxConverter extends Converter[Baz, Qux] {
def convert(a : Baz) : Qux = new Qux
}
import scala.language.implicitConversions
implicit def FooToBar[A <: Foo, B <: Bar](a : A)(implicit converter : Converter[A, B]) : B = converter.convert(a)
val a : Baz = new Baz
val b : Qux = a
// Exiting paste mode, now interpreting.
defined class Foo
defined class Baz
defined class Bar
defined class Qux
defined trait Converter
defined object BazToQuxConverter
import scala.language.implicitConversions
FooToBar: [A <: Foo, B <: Bar](a: A)(implicit converter: Converter[A,B])B
a: Baz = Baz@4f4db2ac
b: Qux = Qux@760d62e0
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