J  Calbreath
J Calbreath

Reputation: 2705

Scala: Return multiple data types from function

This is somewhat of a theoretical question but something I might want to do. Is it possible to return multiple data data types from a Scala function but limit the types that are allowed? I know I can return one type by specifying it, or I can essentially allow any data type by not specifying the return type, but I would like to return 1 of 3 particular data types to preserve a little bit of type safety. Is there a way to write an 'or' in the return type like:

def myFunc(input:String): [Int || String] = { ...}

The main context for this is trying to write universal data loading script. Some of my users use Spark, some Scalding, and who knows what will be next. I want my users to be able to use a generic loading script that might return a RichPipe, RDD, or some other data format depending on the framework they are using, but I don't want to throw type safety completely out the window.

Upvotes: 2

Views: 6280

Answers (3)

bjfletcher
bjfletcher

Reputation: 11518

I'd make the typing by the user less implicit and more explicit. Here are three examples:

def loadInt(input: String): Int = { ... }

def loadString(input: String): String = { ... }

That's nice and simple. Alternatively, we can have a function that returns the appropriate curried function using an implicit context:

def loader[T]()(implicit context: String): String => T = {
  context match {
    case "RDD" => loadInt _ // or loadString _
  }
}

Then the user would:

implicit val context: String = "RDD" // simple example
val loader: String => Int = loader()
loader(input)

Alternatively, can turn it into an explicit parameter:

val loader: String => Int = loader("RDD")

Upvotes: 1

Dmitry  Meshkov
Dmitry Meshkov

Reputation: 931

As already noted in comments you'd better use Either for this task, but if you really want it, you can use implicits

  object IntOrString {
    implicit def fromInt(i: Int): IntOrString = new IntOrString(None, Some(i))
    implicit def fromString(s: String): IntOrString = new IntOrString(Some(s), None)
  }
  case class IntOrString(str: Option[String], int: Option[Int])
  implicit def IntOrStringToInt(v: IntOrString): Int = v.int.get
  implicit def IntOrStringToStr(v: IntOrString): String = v.str.get

  def myFunc(input:String): IntOrString = {
    if(input.isEmpty) {
      1
    }  else {
      "test"
    }
  }

  val i: Int = myFunc("")
  val s: String = myFunc("123")
  //exception
  val ex: Int = myFunc("123")

Upvotes: 1

Conrad
Conrad

Reputation: 571

You can use the Either type provided by the Scala Library.

def myFunc(input:String): Either[Int, String] = {
    if (...) 
        Left(42) // return an Int
    else
        Right("Hello, world") // return a String
}

You can use more than two types by nesting, for instance Either[A,Either[B,C]].

Upvotes: 12

Related Questions