bert123
bert123

Reputation: 35

Scala: return different type depending on parameter - withouth casting

I'm trying to write a function that, based on the parameter passed in, can return different types. To use a really simple example, this is the ideal situation I'm aiming for: Given objects such as these:

case object NameToken
case object SalaryToken
case object IsDirectorToken

and

val john: Employee

then:

Below are a couple of possible implementations that I thought of. It goes without saying that both are horrible.

Possible implementation 1:

trait Token[A]
case object NameToken extends Token[String]
case object SalaryToken extends Token[Int]
case object IsDirectorToken extends Token[Boolean]

case class Employee(name: String, salary: Int, isDirector: Boolean) {
  def get[A](t: Token[A]): A = t match {
    case NameToken => name.asInstanceOf[A]
    case SalaryToken => salary.asInstanceOf[A]
    case IsDirectorToken => isDirector.asInstanceOf[A]
  }
}

Possible implementation 2:

trait Token2 {
  type returnType
}
case object NameToken2 extends Token2 {
  type returnType = String
}
case object SalaryToken2 extends Token2 {
  type returnType = Int
}
case object IsDirectorToken2 extends Token2  {
  type returnType = Boolean
}

case class Employee2(name: String, salary: Int, isDirector: Boolean) {
  def get(t: Token2): t.returnType = t match {
    case NameToken2 => name.asInstanceOf[t.returnType]
    case SalaryToken2 => salary.asInstanceOf[t.returnType]
    case IsDirectorToken2 => isDirector.asInstanceOf[t.returnType]
  }
}

Both of them, however, are just awful with that casting.

Can I solve this problem a little more smartly?

Thank you.

Upvotes: 2

Views: 787

Answers (2)

Dave Swartz
Dave Swartz

Reputation: 910

class Employee(val name: String, val salary: Int, val isDirector: Boolean) {
  def get[T](t: Token[T]): T = t.value(this)
}

trait Token[T] { def value(e: Employee): T }
object NameToken extends Token[String] { def value(e: Employee) = e.name }
object SalaryToken extends Token[Int] { def value(e: Employee) = e.salary }
object IsDirectorToken extends Token[Boolean] { def value(e: Employee) = e.isDirector }

Usage

scala> val john = new Employee("John", 50000, false)
john: Employee = Employee@59f99ea

scala> val name = john.get(NameToken)
name: String = John

scala> val salary = john.get(SalaryToken)
salary: Int = 50000

scala> val isDirector = john.get(IsDirectorToken)
isDirector: Boolean = false

Upvotes: 5

Thomas Krieger
Thomas Krieger

Reputation: 1633

You could use overloading:

  case class Employee(name: String, salary: Int, isDirector: Boolean) {
  def get(t: Token[String]) = name;
  def get(t: Token[Int]) = salary;
  def get(t: Token[Boolean]) = isDirector;
  }    

Upvotes: 1

Related Questions