Type parameter bounding for T and List[T]

127 Views Asked by At

I have a case class with 2 type parameters

case class Relation[T <: Model, RT] (model: T) 

Type T obviously is a type of class property 'model'. Type RT can be the same as T or it can be List[T] (depends on what type of Relation we create OneToOne or OneToMany). So how can i limit RT, that it would not allow to pass something else except T or List[T].

PS I was reading about covariance and contravariance, but did not understand much. Is it appliable in my case? If yes, could you please provide an example. If not - then please show other tools to reach it. I can not even understand how T and List[T] relate to each other? T <: List[T] or List[T] <: T?

Thanks in advance

2

There are 2 best solutions below

1
On BEST ANSWER

Thinking about T <: List[T], List[T] <: T and covariance you're trying to solve your problem using OOP/subtype polymorphism.

In Scala 2 you can try a type class (ad hoc polymorphism)

case class Relation[T <: Model, RT](model: T)(implicit sel: Selector[T, RT])

trait Selector[T <: Model, RT]
object Selector {
  implicit def single[T <: Model]: Selector[T, T] = null
  implicit def multiple[T <: Model]: Selector[T, List[T]] = null
}

How to define "type disjunction" (union types)?

1
On

In Scala 3 you could use union types with generalised constraints

case class Relation[T <: Model, RT](model: T)(using (RT =:= T) | (RT =:= List[T]))

for example

scala> class Model
     | case class Relation[T <: Model, RT](model: T)(using (RT =:= T) | (RT =:= List[T]))
// defined class Model
// defined case class Relation

scala> val v = new Model
val v: Model = Model@51c26394

scala> Relation(v)
val res15: Relation[Model, Model] = Relation(rs$line$29$Model@51c26394)

scala> Relation[Model, List[Model]](v)
val res16: Relation[Model, List[Model]] = Relation(rs$line$29$Model@51c26394)

scala> Relation[Model, 42](v)
1 |Relation[Model, 42](v)
  |                      ^
  |no implicit argument of type (42 : Int) =:= Model | (42 : Int) =:= List[Model] was found for parameter x$2 of method apply in object Relation