0

Is it possible to define a type alias which represent mutliple data types?

package object scala {
  type SingleDimension = Double
  type MultiDimensionMap = Map[String, Double]
  type MultiDimensionList = List[Tuple2[String, Double]]
}

e.g. I need a suptertype lets say DataDimension that represent only above three types. so I can do following:

trait AbstractDataWorker[T] {

  def formula(d: Double): T
}


class multiDimensionWorker extends AbstractDataWorker[MultiDimensionMap] {

  type T = MultiDimensionMap
  override def formula(d: Double): MultiDimensionMap = {

    Map[String, Double]()
  }

}

class singleDimensionWorker extends AbstractDataWorker[SingleDimension] {

  type T = SingleDimension
  override def formula(d: Double): SingleDimension = {
    2.0
  }

}

But following should give compile error. Currently it works.

class stringDimensionWorker extends AbstractDataWorker[String] {

  type T = String
  override def formula(d: Double): String = {

    "hello"
  }

}
nir
  • 3,743
  • 4
  • 39
  • 63

1 Answers1

5

You can make them real classes extending a single trait instead of type aliases:

sealed trait DimensionLike
case class SingleDimension(value: Double) extends DimensionLike
case class MultiDimensionMap(value: Map[String, Double]) extends DimensionLike
case class MultiDinmensionList(value: List[(String, Double)]) extends DimensionLike

abstract class AbstractDataWorker[T <: DimensionLike] {
  def formula(d: Double): T
}

class MultiDimensionWorker extends AbstractDataWorker[MultiDimensionMap] {
  // ...
}

Or you can make a typeclass with implicit implementations for those type aliases. Then make AbstractDataWorker an abstract class, and add a context bound for this typeclass to its type argument:

type SingleDimension = Double
type MultiDimensionMap = Map[String, Double]
type MultiDimensionList = List[(String, Double)]

sealed trait IsDimensionLike[T]
object IsDimensionLike {
  implicit object singleDimension extends IsDimensionLike[SingleDimension]
  implicit object multiDimensionMap extends IsDimensionLike[MultiDimensionMap]
  implicit object multiDimensionList extends IsDimensionLike[MultiDimensionList]
}

abstract class AbstractDataWorker[T : IsDimensionLike] {
  def formula(d: Double): T
}

class MultiDimensionWorker extends AbstractDataWorker[MultiDimensionMap] {
  // ...
}
Kolmar
  • 14,086
  • 1
  • 22
  • 25
  • awesome! I thought of first solution but defining extra 'value' parameter and returning case class instead of simple type like map, list or double didn't look appealing. Second solution is right on but I can't comprehend it :( Can you explain semantics of what's happening there or point me to some reference docs. I am thrown off by many things there: "implicit object singleDimension" is that a companion object to some sort of internal SingleDimension class?; what's T : IsDimensionLike ? When I return Double(2.0) from my SingleDimensionWorker what's happening behind the scene ? – nir Sep 04 '15 at 22:32
  • @nir Google "scala typeclass pattern". Basically `AbstractDataWorker[T : IsDimensionLike]` is syntax sugar for `AbstractDataWorker[T](implicit ev: IsDimensionLike[T])` (that's why you need `abstract class`, traits can't take arguments). To make an `AbstractDataWorker` of some type, the compiler must be able to find an implicit value `IsDimensionLike` of that type. One of the places it searches in is the companion object of the type it needs (`IsDimensionLike`). And in it there are only implicits for the types you allow. `IsDimensionLike` is `sealed` to prohibit allowing other types elsewhere. – Kolmar Sep 04 '15 at 23:14