yhylord
yhylord

Reputation: 420

Simplify pattern matching on type class instances with a certain member

I have this framework that defines a type class with most instances having a certain implicit value:

import scala.reflect.runtime.universe.TypeTag

sealed trait Source

// many classes with implicit TypeTag
case class SourceA[T]()(implicit val ev: TypeTag[T]) extends Source
case class SourceB[T]()(implicit val ev: TypeTag[T]) extends Source
case class SourceC[T]()(implicit val ev: TypeTag[T]) extends Source
// a few classes without TypeTag
case class EmptySource() extends Source

In my app, I would like to access ev in the above example using simple code. Here's what I've come up with:

def retrieveTypeTagFromSource(source: Source): Option[TypeTag[_]] = source match {
  case s: SourceA[_] => Some(s.ev)
  case s: SourceB[_] => Some(s.ev)
  case s: SourceC[_] => Some(s.ev)
  // many more nearly identical lines
  // then handling the remaining classes
  case s: EmptySource => None
}

There are a lot of repetitions, not ideal. I would like to eliminate them without merely transferring the repetitions to the framework side (e.g. adding a HasTypeTag trait to every applicable case class). I tried using the following line when pattern matching:

case s: {val ev: TypeTag[Any]} => Some(s.ev)

but Scala warns a pattern match on a refinement type is unchecked, so I don't know if that actually works.

Upvotes: 1

Views: 61

Answers (1)

Tim
Tim

Reputation: 27356

Adding something like HasTypeTag does not have to be repetitious, just have two different traits and extend TaggedSource or UntaggedSource as appropriate.

import scala.reflect.runtime.universe.TypeTag

sealed trait Source
{
  def ott: Option[TypeTag[_]]
}

abstract class TaggedSource[T]()(implicit val tt: TypeTag[T]) extends Source {
  def ott = Some(tt)
}

trait UntaggedSource extends Source {
  def ott = None
}

// many classes with implicit TypeTag
case class SourceA[T]()(implicit val ev: TypeTag[T]) extends TaggedSource[T]
case class SourceB[T]()(implicit val ev: TypeTag[T]) extends TaggedSource[T]
case class SourceC[T]()(implicit val ev: TypeTag[T]) extends TaggedSource[T]
// a few classes without TypeTag
case class EmptySource() extends UntaggedSource

def retrieveTypeTagFromSource(source: Source): Option[TypeTag[_]] =
                  source.ott

Upvotes: 1

Related Questions