Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

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.

like image 881
Imran Rashid Avatar asked Jan 31 '13 08:01

Imran Rashid


People also ask

Can a scala trait take parameters?

Unlike a class, Scala traits cannot be instantiated and have no arguments or parameters. However, you can inherit (extend) them using classes and objects.

What is Union in scala?

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 .

Can scala trait have variables?

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.

What is .type in scala?

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.


1 Answers

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.

like image 120
Travis Brown Avatar answered Sep 23 '22 22:09

Travis Brown