Search code examples
scalatypestype-systems

Scala - return a type


I want to return a type from a function. For example:

class Super
case class One(a: Int) extends Super
case class Two(b: Float) extends Super
case class Unknown extends Super

def decide(criterion: String): ??? = {
  criterion match {
    case "one" => One
    case "two" => Two
    case _ => Unknown
  }
}

So I want to return the type itself, to store it in a Map so that I could apply it somewhere later:

val test = Buffer(
  ("ahaha" -> "one")
  ("ohoho" -> "two")
  ("lalala" -> "one")
)

var map = scala.collection.mutable.Map[String, Super]()

test.map {pair =>
  map(pair._1) = decide(pair._2)
}

So that later I could like:

def act(code: String) {
  map(code) match {
    case One => doSmth[One]()
    case Two => doSmth[Two]()
    case _ => doNothing()
  }
}

I know that some parts, like the unused parameters of the case classes may seem strange here, but this is how it is in the environment I am working in, and this example is that full because I am not sure if it will differ if I take something away...

So how can I make the decide function return a type and then use it in a manner similar to what I have shown?


Solution

  • I think you may want case object One, etc, rather than using Class or ClassTag. Then you get useful match support. For the act method, your case objects could return a ClassTag or similar, or just let act associate One with doSmth[OneClass] etc.

    It seems you can make your case companions into case objects. Isn't that special.

    package typeswitch
    import reflect.runtime.universe._
    
    sealed trait Selection
    
    class Super
    case class One(a: Int) extends Super
    case object One extends Selection
    case class Two(b: Float) extends Super
    case object Two extends Selection
    case class Unknown() extends Super
    case object Unknown extends Selection
    
    object Test extends App {
      type What = Selection
    
      def decide(criterion: String): What = criterion match {
        case "one" => One
        case "two" => Two
        case _ => Unknown
      }
    
      val test = List(
        "ahaha" -> "one",
        "ohoho" -> "two",
        "lalala" -> "one"
      )
    
      val m = scala.collection.mutable.Map[String, What]()
    
      test map (pair => m(pair._1) = decide(pair._2))
    
      def act(code: String) = m(code) match {
        case One => doSmth[One]()
        // non-exhaustive
        //case Two => doSmth[Two]()
        case Unknown => doNothing()
        // handle exhaustively
        case s: Selection => doSmthNew(s)
      }
      def doSmthElse[A <: Super]()(implicit t: TypeTag[A]): A = {
        Console println s"Do st with $t"
        val claas: Class[_] = t.mirror.runtimeClass(t.tpe)
        null.asInstanceOf[A]
      }
      def doSmth[A <: Super]()(implicit t: ClassTag[A]): A = {
        Console println s"Do st with $t"
        val claas: Class[_] = t.runtimeClass
        null.asInstanceOf[A]
      }
      def doSmthNew[A >: What : ClassTag, B <: Super](what: A): B = {
        Console println s"Do st new with $what"
        null.asInstanceOf[B]
      }
      def doNothing() { }
    
      val res = act("lalala")
      Console println s"Got $res?"
    }