Is there some way in scala that I can return a type?

146 Views Asked by At

I have a lot of classes such as DataFrameFlow, TextFlow, RDDFlow. They all derive from base class Flow.

Now I want to write a function judgeFlow which can read from a path: String and return something representing exact Flow type from which I can create corresponding instance. The whole code seems like the following

def judgeFlow(path:String) = /*1*/ {
  Flow.getStoreType(path) match {
    case StoreType.tdw =>
      DataFrameFlow
    case StoreType.hdfs =>
      TextFlow
  }
}

def createFlow(typeInfo:/*2*/) = /*3*/{
  new typeInfo()
}

However, I don't know how to write in place 1, 2 and 3.

EDIT

Knowing how to construct them is not enough here, because I also want the following:

  1. pattern matching through typeInfo
  2. some ways to do asInstanceOf

EDIT 2

Definition of Flow

abstract class Flow(var outputName: String) extends Serializable{
  def this() = this("")
...
}

Definition of DataFrameFlow

class DataFrameFlow(d: DataFrame, path: String) extends Flow {
  var data: DataFrame = d

  def this(data: DataFrame) = this(data, "")
  def this(path: String) = this(null, path)
  def this() = this(null, "")
...
}
1

There are 1 best solutions below

8
On BEST ANSWER

Pattern matching can't return different types from different cases. The type returned by pattern matching is the least upper bound of types returned in cases.

When someone wants to return different types, most probably he/she wants a type class.

sealed abstract class Flow
class DataFrameFlow extends Flow
class TextFlow extends Flow
class RDDFlow extends Flow

trait JudgeFlow[In] {
  type Out <: Flow
  def judgeFlow(in: In): Out
}
object JudgeFlow {
  implicit val `case1`: JudgeFlow[???] { type Out = DataFrameFlow } = ???
  implicit val `case2`: JudgeFlow[???] { type Out = TextFlow } = ???
  implicit val `case3`: JudgeFlow[???] { type Out = RDDFlow } = ???
}
  
def judgeFlow[In](in: In)(implicit jf: JudgeFlow[In]): jf.Out = jf.judgeFlow(in)

But the trouble is that types are resolved at compile time. You seem to want to choose a case based on a value of string i.e. at runtime. So you can't return more specific types than just Flow at compile time.

flatMap with Shapeless yield FlatMapper not found


It's hard to guess your use case completely.

But using Scala reflection you can try

import scala.reflect.runtime.universe._
import scala.reflect.runtime.currentMirror

def judgeFlow(path:String): Type = {
  Flow.getStoreType(path) match {
    case StoreType.tdw =>
      typeOf[DataFrameFlow]
    case StoreType.hdfs =>
      typeOf[TextFlow]
  }
}

def createFlow(typeInfo: Type): Flow = {
  val constructorSymbol = typeInfo.decl(termNames.CONSTRUCTOR).asMethod
  val classSymbol = typeInfo.typeSymbol.asClass
  val classMirror = currentMirror.reflectClass(classSymbol)
  val constructorMirror = classMirror.reflectConstructor(constructorSymbol)
  constructorMirror().asInstanceOf[Flow]
}