简体   繁体   中英

Scala: Function returning an unknown type

If I wanted to make an add method that adds values of two different types like:

add[T,S](op1: T, op2: S): ? = ...

The most notable example I can think of are the basic number types. If I add a Byte and an Int then it would return an Int. If two Bytes are added it could return an Int depending on if the -127 to 128 limit for the Byte is broken.

Further more if I wanted to create classes that had the same characteristics I would like it to do the same.

One possible solution is to have classes extend the same trait or class. But for the example of Scala primitive types this doesn't apply cause Int, Double, Float, Byte don't share a common ancestor besides Any.

I've also looked at the Numeric[T] trait but that doesn't seem to help when adding different primitive types.

Thanks Kai

This is a prime example for a some kind of joint-typeclass.

Start by defining a thing just like Numeric[T] , but for addability:

trait Addable[T, S] {
  type Result
  def add(x: T, y: S): Result
}

Now, define your add function:

def add[T,S](op1: T, op2: S)(implicit op: Addable[T, S]): op.Result =
  op.add(op1, op2)

All you have to do left, is to create implicit instances for Addable :

// Put them in the companion object, so the implicits are available
// without explicit import
object Addable {
  // Make any numeric addable
  implicit def numericAddable[T : Numeric]: Addable[T, T] = {
    new Addable[T, T] {
      type Result = T
      def add(x: T, y: T): T = {
        val op = implicitly[Numeric[T]]
        op.plus(x, y)
      }
    }
  }
}

But you now can also define your own classes and define (assymetric) addition capability:

case class A(x: Int)
case class B(x: Int)
case class C(x: Int)

implicit object AddABC extends Addable[A,B] {
  type Result = C
  def add(x: A, y: B): C = C(x.x + y.x)
}

This will allow you to write:

add(A(1), B(2))

However, any of these will fail at compile time:

add(A(1), A(2))
add(B(1), A(2))
add(B(1), B(2))

Unfortunately, this does not work for weak conforming numeric types:

add(1, 1) // compiles
add(1.0, 1.0) // compiles
add(1, 1.0) // fails to compile

Judging from another post , there is not really another way to achieve that, than to define the cases manually (with some helper methods of course).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM