0

I'm trying to come up with a generic function that can take primitive data types and also other objects that extends scala.math.Ordering. I checked How to get to type parameters of a reflect.runtime.universe.Type in scala? and I want to get the type of a variable at runtime and I could't get my answer. Example below: import scala.reflect.runtime.universe._ import scala.collection.SortedSet

def getTypeTag[T: TypeTag](obj: T) = typeTag[T]

def createSortedSet[A: TypeTag](y: A) = typeOf[A] match{
//handle the primitive data types 
case t1 if t1 =:= typeOf[Int] =>
SortedSet(y)(implicitly[Ordering[Int]].reverse)
case t2 if t2 =:= typeOf[Long] =>
SortedSet(y)(implicitly[Ordering[Long]].reverse)
.....
// last part handle any object that implements Comparable
case tx if tx.getClass.getInterfaces.exists( _.toString == "interface java.lang.Comparable") =>
{// trying to get the type of the variable and then pass in to the Ordering
 val TT: Type = getTypeTag(t).tpe
SortedSet(y)(implicitly[Ordering[TT]].reverse)}
case _ => ...
}

so in order to pass in a object and let the Ordering do its job, I need to pass in the type to the Ordering, Say I create a case class that extends Ordering

case class Value(i: Int) extends Ordered[Value] {def compare(that: Value) = this.i - that.i}
val v1 = Value(3)
// now I want to get a SortedSet instance by calling the createSortedSet
 createSortedSet(v1)

I got error when I made the above call, so I think reflect.runtime.universe.Type is not really can be used as Type. Is my approach wrong?

Community
  • 1
  • 1
EdwinGuo
  • 1,765
  • 2
  • 21
  • 27

1 Answers1

2

You can make it much simpler:

 def sortedSet[T : Ordering](t:T) = SortedSet(t)(implicitly[Ordering[T]].reverse)

That works for the use case you describe, don't need to differentiate between primitives and other objects, or get the actual type at runtime. When calling this function, the compiler will make sure there's an Ordering available for the type being used (Or fail if there's not). In your case with Value, he will implicitly provide one, based on your implementation of Ordered

Chirlo
  • 5,989
  • 1
  • 29
  • 45
  • Thanks for your answer, works like a charm! so in Scala, [T : Ordering] is saying that the type T is extends trait Ordering? – EdwinGuo Aug 10 '15 at 13:46
  • No, that would be `[T <: Ordering[T]]`. `[T : Ordering]` means that there's an implementation of `Ordering[T]` in scope when compiling the method call. However if a class implements `Ordered`, the compiler will automatically use it to provide this `Ordering`. If this sounds confusing, try reading more about scala implicits. – Chirlo Aug 10 '15 at 13:53
  • When I define the sortedSet like this: "def sortedSet[T <: Ordering[T]](t:T) = SortedSet(t)(implicitly[Ordering[T]].reverse)", it will throw error "starting with method comparatorToOrdering in trait LowPriorityOrderingImplicits." Anyway, so what I really want to tell the compiler is that the type T has Ordering implementation rather then tell the compiler the hierarchy between T and Ordering, so [T : Ordering] is enough and don't bother with [T : Ordering[T]]? – EdwinGuo Aug 10 '15 at 14:03
  • @EdwinGuo Chirlo's answer actually uses [Context bound](http://docs.scala-lang.org/tutorials/FAQ/context-and-view-bounds.html) in Scala. Another verbose style of the answer is ```def sortedSet[T](t:T)(implicit evidence: Ordering[T]) = SortedSet(t)(evidence.reverse)```, when you construct a SortedSet, Scala compiler requires an ```implicit ord: Ordering[A]```. Writing ```T : Ordering``` telling compiler to find the implicit value Ordering[T]. – Allen Chou Aug 10 '15 at 15:11
  • @AllenChou Thanks for your answer, gonna read more on the Type Parameterization. – EdwinGuo Aug 10 '15 at 15:15
  • @EdwinGuo, if you were to use the `def sortedSet[T <: Ordering[T]](t:T)` signature, there would be no implicit `Ordering` but your type `T` would be an ordering itself. So the implementation would be `SortedSet(t)(t.reverse)`, which looks weird but means: Create a `SortedSet` with the element `t`, and use `t` to order it in reverse. It's not a very normal situation, normally you have an `Ordering` separate of your type. It's like javas `Comparator` if that helps you: You define a `Comparator` to compare `Integer`s – Chirlo Aug 10 '15 at 20:04