Reputation: 1
I would like to create an Array (or List, ArrayBuffer, etc) which can only contain instance of classes with defined implicit Ordering (e.g. Int, Long, Double).
Something like this:
val ab = new ArrayBuffer[???]()
ab += 7
ab += 8.9
ab += 8L
I don't want to compare these values with each other.
Upvotes: 0
Views: 1062
Reputation: 15086
If you really want to have a list of objects of different types and still be able to statically check things about the objects in that list at compile time, you would have to use something like a HList
from shapeless. Here is an example of how you could have two heterogeneous lists and still check at compile time that each ith element of both lists can be compared with each other.
import shapeless._
import shapeless.ops.hlist.{LiftAll, Zip, Mapper}
object lt extends Poly1 {
implicit def instance[A] = at[(Ordering[A], A, A)] {
case (ord, a, b) => ord.lt(a, b)
}
}
def areLessThan[L <: HList, O <: HList, OLL <: HList](a: L, b: L)(
implicit
ord: LiftAll.Aux[Ordering, L, O],
zip: Zip.Aux[O :: L :: L :: HNil, OLL],
map: Mapper[lt.type, OLL]
) = zip(ord.instances :: a :: b :: HNil).map(lt)
Using it:
scala> val a = 1 :: "b" :: Option(4L) :: HNil
a: Int :: String :: Option[Long] :: shapeless.HNil = 1 :: b :: Some(4) :: HNil
scala> val b = 2 :: "a" :: Option(7L) :: HNil
b: Int :: String :: Option[Long] :: shapeless.HNil = 2 :: a :: Some(7) :: HNil
scala> areLessThan(a, b)
res10: Boolean :: Boolean :: Boolean :: shapeless.HNil = true :: false :: true :: HNil
Upvotes: 0
Reputation: 14825
Just use the type class constraint as shown below
def createList[T: Ordering](values: T*) = values.toList
T: Ordering
implies only type which has Ordering
instance in scope are allowed to be passed as arguments to the function.
scala> def createList[T: Ordering](values: T*) = values.toList
createList: [T](values: T*)(implicit evidence$1: Ordering[T])List[T]
scala> case class Cat()
defined class Cat
scala> createList(1, 2, 3)
res2: List[Int] = List(1, 2, 3)
scala> createList(Cat())
<console>:15: error: No implicit Ordering defined for Cat.
createList(Cat())
^
Integer ordering is available in scope but cat ordering is not available in scope. So you cannot pass Cat
values until you provide instance of Ordering[Cat]
Now lets provide some fake ordering and see if compiler accepts Cat
as argument
scala> implicit val orderingCat: Ordering[Cat] = (a: Cat, b: Cat) => ???
orderingCat: Ordering[Cat] = $anonfun$1@6be766d1
scala> createList(Cat())
res4: List[Cat] = List(Cat())
It works.
Upvotes: 1