简体   繁体   中英

How to limit class type parameter with specific tuples? (Scala 2.10.4)

I would like to limit type [R] with only specific tuples which are listed somewhere. My main goal is: to ensure that compiler raises an error if any other tuple rather than one of expected is passed to the following trait.

trait QV_Storable[R <: QV_Cue] {
    val prefix: String
    val tableName = prefix.concat(Random.alphanumeric take 8 mkString)
    def Make(rows: Iterable[R.storageColumns]): String 
}

Then I do expect QV_Storable accept only tuples listed in SegmentCue because it is subtupe of QV_Cue . Pay attention that I pass R.storageColumns to Make(rows: Iterable[R.storageColumns]) . Thus, I do expect a way to access parameters of class type.

trait QV_Cue{
    type storageColumns <: Product
    type metaColumns <: Product
}
object SegmentCue extends QV_Cue {
    type storageCols = (CoreDataID, String)
    type metaCols = (Int, String, Date, Int)
}

Is there anyway to limit it this way? It would not be great to subtype from Tuple1, Tuple3, etc.

You can provide a type class, which only sufficient tuples implement:

trait Ok[T] {}

// (Int, Int) is Ok
implicit val tupleIntIntOk: Ok[(Int, Int)] = new Ok[(Int, Int)] {}

// (String, _) is Ok too
implicit def tupleStringAOk[A]: Ok[(String, A)] = new Ok[(String, A)] {}

trait QV_Storable[R] {
  def method(implicit rok: Ok[R]): Unit
  // ...
}

In this scenario you can't call QV_Storable.method if there aren't rok value of the right type in the scope.

This way you can create QV_Storable with any R , but can't actually use any without proper Ok .


A bit different approach is to make similar trick on type-level. Yet there aren't implicit resolution:

sealed trait Ok[T] {}

case class TupleIntIntOk() extends Ok[(Int, Int)]
case class TupleStringAOk[A]() extends Ok[(String, A)]

trait QV_Storable[R, OkR <: Ok[R]] {
  val prefix: String
  // ...
}

// compiles
val foo = new QV_Storable[(Int, Int), TupleIntIntOk] { val prefix = "xy" }

// doesn't
val bar = new QV_Storable[(Int, String), /* nothing to put here */] { val prefix = "bar "}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM