I'm working on a generic conversion library and I'd like to add automatic typeclass derivation using shapeless. It works in the general case but I'd like to introduce Haskellesque newtypes with automatic unwrapping and so I'd like to specialize the deriving function for my NewType type but scalac still picks up the more generic implicit value. Here's the code so far:
import shapeless._, shapeless.syntax._
trait NewType[A] { val value: A }
sealed trait ConversionTree
case class CInt(value: Int) extends ConversionTree
case class CBoolean(value: Boolean) extends ConversionTree
case class CString(value: String) extends ConversionTree
case class CArray(value: List[ConversionTree]) extends ConversionTree
case class CObject(values: Map[String, ConversionTree]) extends ConversionTree
def mergeCObjects(o1: CObject, o2: CObject): CObject = CObject(o1.values ++ o2.values)
trait ConvertsTo[A] {
def convertTo(value: A): ConversionTree
}
object ConvertsTo {
implicit val intConverter = new ConvertsTo[Int] { ... }
implicit val boolConverter = new ConvertsTo[Boolean] { ... }
implicit val stringConverter = new ConvertsTo[String] { ... }
implicit def arrayConverter[A](implicit convertInner: ConvertsTo[A]) = new ConvertsTo[List[A]] { ... }
implicit def objectConverter[A](implicit convertInner: ConvertsTo[A]) = new ConvertsTo[Map[String, A]] { ... }
implicit def newTypeConverter[A](implicit convertInner: ConvertsTo[A]): ConvertsTo[NewType[A]] = new ConvertsTo[NewType[A]] {
override def convertTo(value: NewType[A]): ConversionTree = {
convertInner.convertTo(value.value)
}
}
implicit def deriveHNil: ConvertsTo[HNil] = new ConvertsTo[HNil] {
override def convertTo(value: HNil): ConversionTree = CObject(Map[String, ConversionTree]())
}
// This is the generic case
implicit def deriveHCons[K <: Symbol, V, T <: HList](
implicit
key: Witness.Aux[K],
sv: Lazy[ConvertsTo[V]],
st: Lazy[ConvertsTo[T]]
): ConvertsTo[FieldType[K, V] :: T] = new ConvertsTo[FieldType[K, V] :: T]{
override def convertTo(value: FieldType[K, V] :: T): ConversionTree = {
val head = sv.value.convertTo(value.head)
val tail = st.value.convertTo(value.tail)
mergeCObjects(CObject(Map(key.value.name -> head)), tail.asInstanceOf[CObject])
}
}
// This is the special case for NewTypes
implicit def deriveHConsNewType[K <: Symbol, V, T <: HList](
implicit
key: Witness.Aux[K],
sv: Lazy[ConvertsTo[V]],
st: Lazy[ConvertsTo[T]]
): ConvertsTo[FieldType[K, NewType[V]] :: T] = new ConvertsTo[FieldType[K, NewType[V]] :: T] {
override def convertTo(value: FieldType[K, NewType[V]] :: T): ConversionTree = {
val head = sv.value.convertTo(value.head.value)
val tail = st.value.convertTo(value.tail)
mergeCObjects(CObject(Map(key.value.name -> head)), tail.asInstanceOf[CObject])
}
}
implicit def deriveInstance[F, G](implicit gen: LabelledGeneric.Aux[F, G], sg: Lazy[ConvertsTo[G]]): ConvertsTo[F] = {
new ConvertsTo[F] {
override def convertTo(value: F): ConversionTree = sg.value.convertTo(gen.to(value))
}
}
}
def convertToG[A](value: A)(implicit converter: ConvertsTo[A]): ConversionTree = converter.convertTo(value)
case class Id(value: String) extends NewType[String]
case class User(id: Id, name: String)
println(s"${ConvertsTo.newTypeConverter[String].convertTo(Id("id1"))}")
println(s"User: ${convertToG(User(Id("id1"), "user1"))}")
Output of the first println: CString("id1")
Output of the second println: CObject(Map("id" -> CObject(Map("value" -> CString("id1"))), "name" -> CString("user1")))
I'd like to get rid of the extra CObject around the id field in the second println. As you can see, calling the newTypeConverter directly results in the correct output but it doesn't work when the NewType is embedded in an object(and if I put a breakpoint in the deriveHConsNewType.convertTo method I can verify that it doesn't get called).
I've tried to define deriveHConsNewType like this as well but it didn't help:
implicit def deriveHConsNewType[K <: Symbol, V, N <: NewType[V], T <: HList](
implicit
key: Witness.Aux[K],
sv: Lazy[ConvertsTo[V]],
st: Lazy[ConvertsTo[T]]
): ConvertsTo[FieldType[K, N] :: T] = new ConvertsTo[FieldType[K, N] :: T] { ... }
Can someone explain me how the implicit search works when this kind of overlap occurs and provide a solution to my problem?
EDIT: Solved the issue by making the type variable of ConvertsTo contravariant, scalac now picks the specialized implicit value.
Solved the issue by making the type variable of ConvertsTo contravariant, scalac now picks the specialized implicit value.
trait ConvertsTo[-A] {
def convertTo(value: A): ConversionTree
}
Related
I'm trying to generate instances of case class using shapeless
This works for generating instances of Foo
case class Foo(x: Int, y: String)
class Context {
val random = new Random()
}
def genInt(context: Context): Int = {
context.random.nextInt()
}
def genString(context: Context): String = {
context.random.nextString(16)
}
object ClassesToGenerators extends Poly1 {
implicit def caseInt = at[Class[Int]](_ => genInt(_))
implicit def caseString = at[Class[String]](_ => genString(_))
}
val gen = Generic[Foo]
val context = new Context()
val classes = classOf[Int] :: classOf[String] :: HNil // can't figure out how to get this hlist programmatically
val generators = classes.map(ClassesToGenerators)
gen.from(generators.zipApply(generators.mapConst(context)))
However, I'm aiming to write something reusable like
def newInstance[T] -> T:
???
which could generate instances of any case classes that takes only int and string parameters.
As mentioned in the code snippet, I'm stuck at getting a hlist of case class attribute types i.e. would like to convert case class Foo(x: Int, y: String) to classOf[Int] :: classOf[String] :: HNil. Any other approaches to this problem are also very appreciated but I'm not looking for a generic way of generating random instances of cases classes (as my use-case is different and used random generator just as an example)
IMHO, Shapeless is better used when you forget about all the fancy stuff and just focus on simple typeclass derivation using HList like this:
import shapeless.{Generic, HList, HNil, :: => :!:}
import scala.util.Random
trait Context {
def random: Random
}
object Context {
object implicits {
implicit final val global: Context = new Context {
override final val random: Random = new Random()
}
}
}
trait Generator[A] {
def generate(context: Context): A
}
object Generator {
final def apply[A](implicit ev: Generator[A]): ev.type = ev
final def generate[A](implicit ev: Generator[A], ctx: Context): A =
ev.generate(ctx)
implicit final val IntGenerator: Generator[Int] =
new Generator[Int] {
override def generate(context: Context): Int =
context.random.nextInt()
}
implicit final val StringGenerator: Generator[String] =
new Generator[String] {
override def generate(context: Context): String =
context.random.nextString(16)
}
implicit final def auto[P <: Product](implicit ev: GeneratorGen[P]): Generator[P] = ev
}
sealed trait GeneratorRepr[R <: HList] extends Generator[R]
object GeneratorRepr {
implicit final val HNilGeneratorRepr: GeneratorRepr[HNil] =
new GeneratorRepr[HNil] {
override def generate(context: Context): HNil =
HNil
}
implicit final def HConsGeneratorRepr[E, T <: HList](
implicit ev: Generator[E], tail: GeneratorRepr[T]
): GeneratorRepr[E :!: T] =
new GeneratorRepr[E :!: T] {
override def generate(context: Context): E :!: T =
ev.generate(context) :: tail.generate(context)
}
}
sealed trait GeneratorGen[P <: Product] extends Generator[P]
object GeneratorGen {
implicit final def instance[P <: Product, R <: HList](
implicit gen: Generic.Aux[P, R], ev: GeneratorRepr[R]
): GeneratorGen[P] = new GeneratorGen[P] {
override def generate(context: Context): P =
gen.from(ev.generate(context))
}
}
Which can be used like this:
import Context.implicits.global
final case class Foo(x: Int, y: String)
val result = Generator.generate[Foo]
// result: Foo = Foo(-2127375055, "鞰Ϗƨ沺㗝䚮Ⴍ욏ꖱꬮӝ闉믃雦峷")
You can see the code running here.
Using built-in Shapeless type classes you can do
import shapeless.ops.hlist.FillWith
import shapeless.{Generic, HList, Poly0}
val context = new Context()
object ClassesToGenerators extends Poly0 {
implicit val caseInt = at[Int](genInt(context))
implicit val caseString = at[String](genString(context))
}
def newInstance[A] = new PartiallyApplied[A]
class PartiallyApplied[A] {
def apply[L <: HList]()(implicit
generic: Generic.Aux[A, L],
fillWith: FillWith[ClassesToGenerators.type, L]
): A = generic.from(fillWith())
}
newInstance[Foo]() // Foo(2018031886,⮐掐禃惌ᰧ佨妞ዤࠒ훿柲籐妭蝱⻤)
I am trying to generate a typeclass for returning the value of a case class field that has a particular annotation at compile time, using shapeless.
That's given a Scala annotation case class and a generic case class the typeclass Identity[T]
should return the value of the 'single' attribute annotated with such an annotation.
trait Identity[T] {
def apply(t: T): Long
}
final case class Id() extends scala.annotation.StaticAnnotation
case class User(#Id id: Long, account_id: Int, name: String, updated_at: java.time.Instant)
and given an instance of the case class and typeclass
val identity = Identity[User] // implicit summoner
val user = User(1009, 101, "Alessandro", Instant.now())
val value = identity(user)
I'd like value to return 1009
I tried to play around the following snippet, but I did get as far as to compute the Symbol name of the annotated field.
object WithShapeless {
import MyAnnotations.Id
import shapeless._
import shapeless.ops.hlist
import shapeless.ops.record.Keys
import shapeless.record._
// select the field symbol with the desired annotation, if exists
object Mapper extends Poly1 {
implicit def some[K <: Symbol]: Case.Aux[(K, Some[Id]), Option[K]] = at[(K, Some[Id])] {
case (k, _) => Some(k)
}
implicit def none[K <: Symbol]: Case.Aux[(K, None.type), Option[K]] = at[(K, None.type)] {
case (k, _) => Option.empty[K]
}
}
implicit def gen[A, HL <: HList, AL <: HList, KL <: HList, ZL <: HList, ML <: HList](
implicit
generic: LabelledGeneric.Aux[A, HL],
annots: Annotations.Aux[Id, A, AL],
keys: Keys.Aux[HL, KL],
zip: hlist.Zip.Aux[KL :: AL :: HNil, ZL],
mapper: hlist.Mapper.Aux[Mapper.type, ZL, ML],
ev0: hlist.ToList[ML, Option[Symbol]]
): Identity[A] = new Identity[A] {
val zipped: ZL = zip(keys() :: annots() :: HNil)
val annotatedFields: ML = mapper.apply(zipped)
val symbol: Symbol = annotatedFields.to[List].find(_.isDefined).get match {
case Some(symbol) => symbol
case _ => throw new Exception(s"Class has no attribute marked with #IdAnnot")
}
println(s"""
|zipped: ${zipped}
|mapped: ${annotatedFields}
|symbol: $symbol
|""".stripMargin)
override def apply(a: A): Long = {
val repr = generic.to(a)
val value = repr.get(Witness(symbol)) // compilation fails here
println(s"""
|Generic ${generic.to(a)}
|value: $value
""".stripMargin)
1
}
}
}
I try to conjure a Selector to return the value but the compiler fails with No field this.symbol.type in record HL.
I cannot get it to work!
Thanks
Actually you don't need LabelledGeneric because you don't use keys. Try
import java.time.Instant
import shapeless.ops.hlist.{CollectFirst, Zip}
import shapeless.{::, Annotations, Generic, HList, HNil, Poly1}
trait Identity[T] {
type Out
def apply(t: T): Out
}
object Identity {
type Aux[T, Out0] = Identity[T] { type Out = Out0 }
def instance[T, Out0](f: T => Out0): Aux[T, Out0] = new Identity[T] {
type Out = Out0
override def apply(t: T): Out = f(t)
}
def apply[T](implicit identity: Identity[T]): Aux[T, identity.Out] = identity
implicit def mkIdentity[T, HL <: HList, AL <: HList, ZL <: HList](implicit
generic: Generic.Aux[T, HL],
annotations: Annotations.Aux[Id, T, AL],
zip: Zip.Aux[HL :: AL :: HNil, ZL],
collectFirst: CollectFirst[ZL, Mapper.type],
): Aux[T, collectFirst.Out] =
instance(t => collectFirst(zip(generic.to(t) :: annotations() :: HNil)))
}
object Mapper extends Poly1 {
implicit def cse[A]: Case.Aux[(A, Some[Id]), A] = at(_._1)
}
final case class Id() extends scala.annotation.StaticAnnotation
case class User(#Id id: Long, account_id: Int, name: String, updated_at: java.time.Instant)
val identity = Identity[User]
val user = User(1009, 101, "Alessandro", Instant.now())
val value = identity(user) // 1009
I have the following code:
sealed trait Animal
case class Cat(name: String) extends Animal
case class Dog(name: String) extends Animal
trait Show[A] {
def show(a: A): String
}
class Processor[A](a: A) {
def print(implicit S: Show[A]): Unit = println(S.show(a))
}
implicit val showCat: Show[Cat] = c => s"Cat=${c.name}"
implicit val showDog: Show[Dog] = d => s"Dog=${d.name}"
val garfield = Cat("Garfield")
val odie = Dog("Odie")
val myPets = List(garfield, odie)
for (p <- myPets) {
val processor = new Processor(p)
processor.print // THIS FAILS AT THE MOMENT
}
Does anyone know of a nice way to get that line processor.print working?
I can think of 2 solutions:
pattern match the p in the for loop.
create an instance of Show[Animal] and pattern match it against all its subtypes.
But I'm wondering if there's a better way of doing this.
Thanks in advance!
Compile error is
could not find implicit value for parameter S: Show[Product with Animal with java.io.Serializable]
You can make Animal extend Product and Serializable
sealed trait Animal extends Product with Serializable
https://typelevel.org/blog/2018/05/09/product-with-serializable.html
Also instead of defining implicit Show[Animal] manually
implicit val showAnimal: Show[Animal] = {
case x: Cat => implicitly[Show[Cat]].show(x)
case x: Dog => implicitly[Show[Dog]].show(x)
// ...
}
you can derive Show for sealed traits (having instances for descendants) with macros
def derive[A]: Show[A] = macro impl[A]
def impl[A: c.WeakTypeTag](c: blackbox.Context): c.Tree = {
import c.universe._
val typA = weakTypeOf[A]
val subclasses = typA.typeSymbol.asClass.knownDirectSubclasses
val cases = subclasses.map{ subclass =>
cq"x: $subclass => _root_.scala.Predef.implicitly[Show[$subclass]].show(x)"
}
q"""
new Show[$typA] {
def show(a: $typA): _root_.java.lang.String = a match {
case ..$cases
}
}"""
}
implicit val showAnimal: Show[Animal] = derive[Animal]
or Shapeless
implicit val showCnil: Show[CNil] = _.impossible
implicit def showCcons[H, T <: Coproduct](implicit
hShow: Show[H],
tShow: Show[T]
): Show[H :+: T] = _.eliminate(hShow.show, tShow.show)
implicit def showGen[A, C <: Coproduct](implicit
gen: Generic.Aux[A, C],
show: Show[C]
): Show[A] = a => show.show(gen.to(a))
or Magnolia
object ShowDerivation {
type Typeclass[T] = Show[T]
def combine[T](ctx: CaseClass[Show, T]): Show[T] = null
def dispatch[T](ctx: SealedTrait[Show, T]): Show[T] =
value => ctx.dispatch(value) { sub =>
sub.typeclass.show(sub.cast(value))
}
implicit def gen[T]: Show[T] = macro Magnolia.gen[T]
}
import ShowDerivation.gen
or Scalaz-deriving
#scalaz.annotation.deriving(Show)
sealed trait Animal extends Product with Serializable
object Show {
implicit val showDeriving: Deriving[Show] = new Decidablez[Show] {
override def dividez[Z, A <: TList, ShowA <: TList](tcs: Prod[ShowA])(
g: Z => Prod[A]
)(implicit
ev: A PairedWith ShowA
): Show[Z] = null
override def choosez[Z, A <: TList, ShowA <: TList](tcs: Prod[ShowA])(
g: Z => Cop[A]
)(implicit
ev: A PairedWith ShowA
): Show[Z] = z => {
val x = g(z).zip(tcs)
x.b.value.show(x.a)
}
}
}
For cats.Show with Kittens you can write just
implicit val showAnimal: Show[Animal] = cats.derived.semi.show
The thing is that garfield and odie in List(garfield, odie) have the same type and it's Animal instead of Cat and Dog. If you don't want to define instance of type class for parent type you can use list-like structure preserving types of individual elements, HList garfield :: odie :: HNil.
For comparison deriving type classes in Scala 3
How to access parameter list of case class in a dotty macro
The most general solution is to just pack the typeclass instances in at the creation of myPets, existentially
final case class Packaged[+T, +P](wit: T, prf: P)
type WithInstance[T, +P[_ <: T]] = Packaged[U, P[U]] forSome { type U <: T }
implicit def packageInstance[T, U <: T, P[_ <: T]]
(wit: U)(implicit prf: P[U])
: T WithInstance P
= Packaged(wit, prf)
val myPets = List[Animal WithInstance Show](garfield, odie)
for(Packaged(p, showP) <- myPets) {
implicit val showP1 = showP
new Processor(p).print // note: should be def print()(implicit S: Show[A]), so that this can be .print()
}
It is a common practice to provide a helper value class for accessing type classes - something like
object Show {
def apply[A](implicit sh: Show[A]): Show[A] = sh
def show[A: Show](a: A) = Show[A].show(a)
implicit class ShowOps[A: Show](a: A) {
def show = Show[A].show(a)
}
implicit val intCanShow: Show[Int] =
new Show[Int] {
def show(int: Int): String = s"int $int"
}
}
In my case, I have a type class with 2 parameters. And I cannot get the value class to work (MapperOps). I keep getting "could not find implicit value for parameter mapper"
trait Mapper[T, D] {
def toDto(i: T): D
}
object Mapper {
def map[T, D](i: T)(implicit mapper: Mapper[T, D]): D = implicitly[Mapper[T, D]].toDto(i)
def apply[T, D](implicit mapper: Mapper[T, D]): Mapper[T, D] = mapper
implicit def optionMapper[T, D](implicit mapper: Mapper[T, D]): Mapper[Option[T], Option[D]] = {
new Mapper[Option[T], Option[D]] {
override def toDto(i: Option[T]): Option[D] = i.map(mapper.toDto)
}
}
implicit def seqMapper[T, D](implicit mapper: Mapper[T, D]): Mapper[Seq[T], Seq[D]] = {
new Mapper[Seq[T], Seq[D]] {
override def toDto(i: Seq[T]): Seq[D] = i.map(mapper.toDto)
}
}
// Neither works
implicit class MapperOps1[T,D](a: T) {
def toDto = Mapper[T,D].toDto(a)
}
implicit class MapperOps2[T,D](a: T) {
def toDto(implicit mapper: Mapper[T,D]) = Mapper[T,D].toDto(a)
}
implicit class MapperOps3[T,D](a: T) {
def toDto[D](implicit mapper: Mapper[T,D]): D Mapper[T,D].toDto(a)
}
}
Notice the important difference that in
implicit class ShowOps[A: Show](a: A) { ... }
you have this A : Show part, which essentially desugares into
implicit class ShowOps[A](a: A)(implicit s: Show[A]) { ... }
Since there is no neat [T : MyTypeClass]-syntax for two-parameter "Type-Pair-Classes", you have to provide the implicit Mapper as a separate
parameter to the constructor:
implicit class MapperOps1[T, D](a: T)(implicit m: Mapper[T, D]) {
def toDto = Mapper[T, D].toDto(a)
}
The following little test compiles and outputs "42":
implicit object IntToStringMapper extends Mapper[Int, String] {
def toDto(i: Int): String = i.toString
}
import Mapper._
val s: String = 42.toDto
println(s)
Alternatively, you could try it with an implicit conversion (compiler will whine at you if you don't enable this feature explicitly, and users will whine at you if you don't use this feature wisely):
class MapperOps1[T,D](a: T, mapperTD: Mapper[T, D]) {
def toDto = {
implicit val m: Mapper[T, D] = mapperTD
Mapper[T,D].toDto(a)
}
}
import scala.language.implicitConversions
implicit def wrapIntoMapperOps1[T, D]
(a: T)
(implicit m: Mapper[T, D]): MapperOps1[T, D] = new MapperOps1(a, m)
I won't comment on your two other attempts: apparently, the compiler cannot instantiate those, because it doesn't get enough information about the type parameters before it has to instantiate a wrapper.
In my application I have multiple case classes and objects which are part of sealed trait hierarchy. I use them as messages in Akka.
Those classes need to be converted to user friendly form before sending through websocket.
Previously I used big pattern match to convert them in single place, but as number of types grows I would like to use implicit conversion:
object Types {
sealed trait Type
case object SubType1 extends Type
case object SubType2 extends Type
case object SubType3 extends Type
trait Converter[T] {
def convert(t: T): Int
}
}
object Implicits {
import Types._
implicit object Type1Coverter extends Converter[SubType1.type] {
override def convert(t: SubType1.type): Int = 1
}
implicit object Type2Coverter extends Converter[SubType2.type] {
override def convert(t: SubType2.type): Int = 2
}
implicit object Type3Coverter extends Converter[SubType3.type] {
override def convert(t: SubType3.type): Int = 3
}
}
object Conversion {
import Types._
def convert[T: Converter](t: T): Int = {
implicitly[Converter[T]].convert(t)
}
def convert2[T <: Type](t: T)(implicit ev1: Converter[SubType1.type], ev2: Converter[SubType2.type], ev3: Converter[SubType3.type]): Int = {
t match {
case t1#SubType1 =>
implicitly[Converter[SubType1.type]].convert(t1)
case t2#SubType2 =>
implicitly[Converter[SubType2.type]].convert(t2)
case t3#SubType3 =>
implicitly[Converter[SubType3.type]].convert(t3)
}
}
}
I would like to use them as follow:
import Types._
import Conversion._
import Implicits._
val t1 = SubType1
val x1: Int = convert(t1)
val t: Type = SubType2 // T is of type Type
//Is it possible to handle that?
//val x: Int = convert(t)
val y: Int = convert2(t)
I would love to know if there is any "magic" way to generate something like convert2 automatically without writing a macro. Maybe there is already a library which provides macro like this?
Since you have no info at compile time about t's type, you have to work at runtime.
if you put your Converters in a sealed family, you could do something like the follwing, using a technique explained in this question:
import shapeless._
trait AllSingletons[A, C <: Coproduct] {
def values: List[A]
}
object AllSingletons {
implicit def cnilSingletons[A]: AllSingletons[A, CNil] =
new AllSingletons[A, CNil] {
def values = Nil
}
implicit def coproductSingletons[A, H <: A, T <: Coproduct](implicit
tsc: AllSingletons[A, T],
witness: Witness.Aux[H]): AllSingletons[A, H :+: T] =
new AllSingletons[A, H :+: T] {
def values = witness.value :: tsc.values
}
}
trait EnumerableAdt[A] {
def values: Set[A]
}
object EnumerableAdt {
implicit def fromAllSingletons[A, C <: Coproduct](implicit
gen: Generic.Aux[A, C],
singletons: AllSingletons[A, C]): EnumerableAdt[A] =
new EnumerableAdt[A] {
def values = singletons.values.toSet
}
}
object Types {
sealed trait Type
case object SubType1 extends Type
case object SubType2 extends Type
case object SubType3 extends Type
sealed abstract class Converter[T <: Type: ClassTag] {
def convert(t: T): Int
def convertibleObjectClass = implicitly[ClassTag[T]].runtimeClass
}
object Implicits {
implicit object Type1Converter extends Converter[SubType1.type] {
override def convert(t: SubType1.type): Int = 1
}
implicit object Type2Converter extends Converter[SubType2.type] {
override def convert(t: SubType2.type): Int = 2
}
// let's pretend you FORGOT to add Type3Converter
// implicit object Type3Converter extends Converter[SubType3.type] {
// override def convert(t: SubType3.type): Int = 3
// }
}
}
object Conversion {
import Types._
val AllConverters: Map[Class[_], Converter[_ <: Type]] = implicitly[EnumerableAdt[Converter[_ <: Type]]].values
.map(c => c.convertibleObjectClass -> c).toMap
// You're sure you have all the converters here but you can't be sure you remembered to add one per subtype... you have to test it
// you are sure this cast doesn't fail anyway because of how you created the map
def findConverter[T <: Type](t: T) = AllConverters.get(t.getClass).asInstanceOf[Option[Converter[T]]]
def convert2[T <: Type](t: T): Option[Int] = findConverter(t).map(_.convert(t))
}
object Test extends App {
import Types._
import Conversion._
val t: Type = SubType2
val t2: Type = SubType3
// works, because a Converter[Subtype2.type] exists
val a: Option[Int] = convert2(t)
// returns None, because a Converter[Subtype3.type] doesn't exist
val b: Option[Int] = convert2(t2)
}