3

I bumped into a code snippet and not able to make sense out of it. The snippet is:

  implicit val dummyVisit = Visit("", 1L, 1, 1, 1, 1L)
  implicit val dummyOrder = Order("", 1L, 1, 1, 1, 1L)

  def process[T](events : Array[T])(implicit t: T):Unit = {
    println(t)
    if(!events.isEmpty)
      t match {
        case r: Order => processOrder(events.asInstanceOf[Array[Order]])
        case r: Visit => processVisit(events.asInstanceOf[Array[Visit]]);
      }
  }

  def processOrder(arr: Array[Order]): Unit = { println(arr.size) }
  def processVisit(arr: Array[Visit]): Unit = { println(arr.size) }

The implicit variable t, requires the dummyVisit & dummyOrder to exist.

Question:

  1. Is this a right way of using implicit parameter?

  2. Is there a better way for get the class-type of T, without using implicit parameter?

2
  • 1
    Implicits are searched using the implicit resolution rules stackoverflow.com/questions/5598085/… I don't understand your question? you can call process(xs) on an array of either Visits or Orders. If the corresponding implicit is not in scope, process(xs) would not compile Commented Feb 12, 2016 at 8:39
  • 1
    Looks like a bad way of using polymorphism or lack thereof Commented Feb 12, 2016 at 9:03

1 Answer 1

5

Capturing the type of an argument is one of the intended uses of implicit arguments.

Though I'd write something like this a bit differently:

import scala.reflect.ClassTag

// `sealed` ensures that no extra evidences can be defined elsewhere
sealed abstract class Evidence[T](implicit val tag: ClassTag[T])
object Evidence {
  implicit object visitEvidence extends Evidence[Visit]
  implicit object orderEvidence extends Evidence[Order]
}

def process[T](events: Array[T])(implicit ev: Evidence[T]) = {
  import ev.tag // import ClassTag[T] to allow matching on array element types
  events match {
    case Array() => // don't process empty arrays
    case arr: Array[Order] => processOrder(arr)
    case arr: Array[Visit] => processVisit(arr)
  }
}

This code avoids creating meaningless dummy instances, and typecasting with asInstanceOf.

A step further would be to capture the processing operation itself in the implicit argument and completely avoid the explicit match for every case. This is also known as typeclass pattern:

sealed trait ProcessArray[T] {
  def apply(arr: Array[T]): Unit
}
object ProcessArray {
  implicit object processVisitArray extends ProcessArray[Visit] {
    def apply(arr: Array[Visit]) = { println(arr.size) }
  }
  implicit object processOrderArray extends ProcessArray[Order] {
    def apply(arr: Array[Order]) = { println(arr.size) }
  }
}
def process[T](array: Array[T])(implicit proc: ProcessArray[T]) = {
  if (array.nonEmpty) proc(array)
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.