1

I am trying to define a map with a parameterized class as its key. But when I try to add to it I get a compiler error:

trait MyTrait[T <: MyTrait[T]]

case class A(i: Int) extends MyTrait[A]
case class B(str: String) extends MyTrait[B]

var map = Map[Class[_ <: MyTrait[_]], Int]()

def update[T <: MyTrait[T]](n: Int) = {
    map += classOf[T] -> n  // Won't compile
}

I get the following compiler error:

  Expression does not convert to assignment because:  
    class type required but T found  
    expansion: map = map.+(classOf[T].<$minus$greater: error>(n))  
        map += classOf[T] -> n  

What is the correct way to extract my class as a key? It compiles fine if I use a concrete class for example:

    map += classOf[A] -> n
Dmytro Mitin
  • 48,194
  • 3
  • 28
  • 66
user79074
  • 4,937
  • 5
  • 29
  • 57
  • 3
    To make `classOf` work with generic you have to specify that you want to have type information in runtime. Usually you need some `ClassTag` magic. – talex Sep 30 '20 at 07:53
  • 1
    The problem here is that `T` is a `type` and not a class, hence `classOf` will not work. You will need to pull the class of the type using reflection. – sarveshseri Sep 30 '20 at 08:17
  • Things like **F-Bound** polymorphism, a mutable map and wanting to use a class as a key are all code smells for me. May I ask what is the meta problem you are trying to solve? – Luis Miguel Mejía Suárez Sep 30 '20 at 12:08

1 Answers1

2

You should add context bound ClassTag and replace classOf[T] with classTag[T].runtimeClass.

classOf[T] works with actual classes (that are known to be classes now, like classOf[Int], classOf[String] etc). For type parameters (that will become class types when a method is called) you need class tags.

def update[T <: MyTrait[T]: ClassTag](n: Int) = {
  val clazz = classTag[T].runtimeClass.asInstanceOf[Class[T]]
  map += clazz -> n
}

println(map) //HashMap()
update[A](1) 
println(map) //HashMap(class A -> 1)
update[B](2)
println(map) //HashMap(class A -> 1, class B -> 2)

https://docs.scala-lang.org/overviews/reflection/typetags-manifests.html

Dmytro Mitin
  • 48,194
  • 3
  • 28
  • 66