Imran Rashid
Imran Rashid

Reputation: 753

Union types as bound for type parameters of a trait (scala)

How can I constrain the type parameters of a trait to be among a distinct set of types (eg., bound by union type)?

As a concrete example, I'd like to create a trait IntegralIndex[T] where T must Int or Long.

I tried the first answer to this question on union types :

sealed abstract class NumericIndex[T]
object NumericIndex {
  implicit object IntWitness extends NumericIndex[Int]
  implicit object LongWitness extends NumericIndex[Long]
}

trait IntegralIndex[T : NumericIndex]

but that doesn't work; I get traits cannot have type parameters with context bounds `: ...' nor view bounds `<% ...'

Any other suggestions? Admittedly, I didn't understand the other solutions to the question on union types, so I'd appreciate if the answer is just to use a different answer there, or even to know that it can't be done.

Upvotes: 8

Views: 862

Answers (1)

Travis Brown
Travis Brown

Reputation: 139058

The type class approach is probably the cleanest way to accomplish what you want here, and you're on the right track with your version. It doesn't work in its current form because context bounds are just syntactic sugar for implicit parameters. The following trait definition, for example:

trait IntegralIndex[T: NumericIndex]

Would be desugared to something like this:

trait IntegralIndex[T](implicit num: NumericIndex[T])

But traits don't have constructors, so this isn't valid Scala syntax. You can, however, write something like this:

trait IntegralIndex[T] {
  implicit def num: NumericIndex[T]
}

This ensures that you can't create a IntegralIndex[T] unless you have evidence that there's an instance of the NumericIndex type class for T.

Now when you're implementing IntegralIndex, you'd write either:

case class MyIndex[T](whatever: String)(implicit val num: NumericIndex[T])

Or:

case class MyIndex[T: NumericIndex](whatever: String) {
  implicit val num = implicitly[NumericIndex[T]]
}

Now all the implicit plumbing is invisible to anyone using MyIndex.

Upvotes: 7

Related Questions