1

This works fine:

def echo[A, B](a: A, b: B): A = ???

This is also fine:

def echo[A, B](a: A, b: B): B = ???

However, how do we achieve this to return either type A or B?

// error
def echo[A, B](a: A, b: B): A|B = ???

Is it simply possible to have a union type of generic types A and B? Cheers.


UPDATE1

Either is an option but not ideal, as it requires a pattern match when processing the returned result. Effectively, I want this: A <: A|B, B <: A|B, which Either does not achieve.

Another extreme, I can do this, but type is too loose:

def echo[A, B](a: A, b: B): Any = ???

UPDATE2
Why I don't want Either?

(Reason 2)

The returned result would actually be a Dataset of Spark, which requires Encoder for any type that is not a subtype of Product (see this topic).

When calling this method many times, it ends up with too many Either wrapping each other, e.g. Either[Either[Either[...]]]. This requires too many encoders to be defined.

So I'm actually doing this:

def echo[A, B](a: A, b: B): Dataset[A|B] = ???

If I do this it would require to have many different encoders due to Either type:

def echo[A, B](a: A, b: B): Dataset[Either[A, B]] = ???
val result1: Either[Cat, Dog] = echo(a: Cat, b: Dog)
val result2: Either[Either[Cat, Dog], Pig] = echo(result1: Either[Cat, Dog], c: Pig)

// we have to define encoders:
implicit encoder1: org.apache.spark.sql.Encoders.kryo[Either[Cat, Dog]]
implicit encoder2: org.apache.spark.sql.Encoders.kryo[Either[Either[Cat, Dog], Pig]]

// if we keep iterating, then too many encoders to define...
jack
  • 1,787
  • 14
  • 30
  • 4
    well, there's [Either](https://www.scala-lang.org/api/2.12.0/scala/util/Either.html) – Dima Mar 07 '21 at 21:25
  • Sounds like function specialization from C++ would have been handy here – smac89 Mar 07 '21 at 21:30
  • @smac89 Thanks for that, good to know. But it seems `@specialized` only works for specific types, meaning it cannot do `def echo[@specialized(A,B) AB](a: A, b: B, ab: AB) = ???` (where `A` and `B` are generic types). Secondly, it seems it cannot return a `@specialized` type e.g. `def echo[A, B](a: A, b: B): @specialized(A,B) = ???` Both errors! – jack Mar 07 '21 at 21:55
  • @Dima Thanks! `Either` is not bad, but it requires a pattern match when processing the returned result. Effectively, I want this: `A <: A|B`, `B <: A|B`, which `Either` does not achieve. – jack Mar 07 '21 at 22:01
  • 1
    Union type also requires a pattern match. – Krzysztof Atłasik Mar 07 '21 at 22:28
  • @jack If you don't know the actual type of the returned value, you are going to have to match in the end to be able to do anything meaningful with it (other than trivial stuff like `print` or `equals`, but for that you could just use `Any`). – Dima Mar 08 '21 at 01:01
  • It seems you have a design problem in your **Spark** code since Scala 2 doesn't really support union types your current approach is doomed. – Luis Miguel Mejía Suárez Mar 08 '21 at 12:32

1 Answers1

2

Soon-to-be-released Scala 3 has it.

def echo[A, B](a: A, b: B): A|B = ???  //this compiles

As can be seen in this Scastie session.

jwvh
  • 50,871
  • 7
  • 38
  • 64
  • Thanks for reaching out. In Scala 2.11, it still does not compile, is there way to achieve this? – jack Mar 07 '21 at 21:28