Search code examples
scalagenericstypestypeclass

scala type bounds and variance


Please explain what princeples of scala typing and why should be use here

I got type hierarchy

class A
class B extends A
class C extends A
cladd D extends C

And other type class

class Hub(init) {
 def add(elem): Hub = new Hub(elem)
}

I need to do edit typing of Hub and Hub.add that it should work like this

val a : Hub[D] = Hub(new D)
val b : Hub[A] = a.add(new B)
val c : Hub[A] = b.add(new C)
val d : Hub[A] = c.add(new D)

And this should be compile error

val e : Hub[C] = b.add(new C)

how should I edit it and why?

P.S. This is not valid scala code, it is for sake of types example


Solution

  • Make add parametric with proper type bounds [B >: A] (see like half the standard library collections' methods for typical examples).

    class Hub[A](a: A) {
     def add[B >: A](b: B): Hub[B] = new Hub[B](b)
    }
    object Hub {
      def apply[A](a: A): Hub[A] = new Hub[A](a)
    }
    
    val a : Hub[D] = Hub(new D)
    val b : Hub[A] = a.add(new B)
    val c : Hub[A] = b.add(new C)
    val d : Hub[A] = c.add(new D)
    // val e : Hub[C] = b.add(new C) type mismatch
    

    In [B >: A](b: B) compiler tries to infer B s that it would both:

    • be a supertype of A
    • be a supertype of a passed value so that it could be upcasted to it