Wieloming Wieloming - 3 months ago 26
Scala Question

Scala nested types with traits

I've got something like this:

trait ObjectId {
val value: Long
}
case class Room(id: Option[Room.Id])

case object Room {
case class Id(value: Long) extends ObjectId
}

case class Tree(id: Option[Tree.Id])

case object Tree {
case class Id(value: Long) extends ObjectId
}


What I want to do is create class
FromDB
with field id, of type which extends trait
ObjectId
and is nested inside
T
:

case class FromDB[T](value: T, id)


for example it should work as follows:

FromDB[Room](Room, Room.Id)
FromDB[Tree](Tree, Tree.Id)

Answer

You could use depenent types and let type inference work for you:

trait ObjectId {
    val value: Long
}

trait Model[T] {
    type Id <: ObjectId
}

case class Room(id: Option[Room.Id])

object Room extends Model[Room] {
    case class Id(value: Long) extends ObjectId
}

case class Tree(id: Option[Tree.Id])

object Tree extends Model[Tree] {
    case class Id(value: Long) extends ObjectId
}

case class FromDB[T, I <: Model[T]](value: T, id: I#Id)

val room = Room(Some(Room.Id(1)))

FromDB(room, room.id.get) // compiles
FromDB(room, Tree.Id(123)) // doesn't compile

Here, Model[T] defines a type Id which is constrained to be a child of ObjectId. Each instance of Model[T] has its own implementation of Id.

In FromDB[T, I <: Model[T]], the compiler will infere I if id is an instance of the correct Model[T], it won't compile otherwise.

Comments