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.
Unlike a class, Scala traits cannot be instantiated and have no arguments or parameters. However, you can inherit (extend) them using classes and objects.
Language. Used on types, the | operator creates a so-called union type. The type A | B represents values that are either of the type A or of the type B .
In scala, trait is a collection of abstract and non-abstract methods. You can create trait that can have all abstract methods or some abstract and some non-abstract methods. A variable that is declared either by using val or var keyword in a trait get internally implemented in the class that implements the trait.
Scala is a statically typed programming language. This means the compiler determines the type of a variable at compile time. Type declaration is a Scala feature that enables us to declare our own types.
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
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With