Общий тип Union без Scala

Это отлично работает:

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

Это тоже нормально:

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

Однако как нам добиться этого, чтобы вернуть либо тип A, либо тип B?

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

Возможно ли просто иметь тип объединения из универсальных типов A и B? Ваше здоровье.


ОБНОВЛЕНИЕ1

Either — вариант, но не идеальный, так как при обработке возвращаемого результата требуется совпадение с шаблоном. По сути, я хочу этого: A <: A|B, B <: A|B, чего Either не достигает.

Другая крайность, я могу сделать это, но шрифт слишком свободный:

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

ОБНОВЛЕНИЕ 2
Почему мне не нужен Either?

(Причина 2)

Возвращаемый результат на самом деле будет Dataset Spark, что требует Encoder для любого типа, который не является подтипом Product (см. эту тему).

При многократном вызове этого метода он приводит к слишком большому количеству Either, обертывающих друг друга, например. Either[Either[Either[...]]]. Для этого требуется определить слишком много кодировщиков.

Итак, я на самом деле делаю это:

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

Если я сделаю это, потребуется много разных кодировщиков из-за типа Either:

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...

person jack    schedule 07.03.2021    source источник
comment
ну, есть Или   -  person Dima    schedule 08.03.2021
comment
Похоже, специализация функций из C++ здесь была бы кстати.   -  person smac89    schedule 08.03.2021
comment
@ smac89 Спасибо за это, приятно знать. Но похоже, что @specialized работает только для определенных типов, то есть он не может выполнять def echo[@specialized(A,B) AB](a: A, b: B, ab: AB) = ??? (где A и B — общие типы). Во-вторых, кажется, что он не может вернуть тип @specialized, например. def echo[A, B](a: A, b: B): @specialized(A,B) = ??? Обе ошибки!   -  person jack    schedule 08.03.2021
comment
@Дима Спасибо! Either неплохо, но требует сопоставления с образцом при обработке возвращаемого результата. По сути, я хочу этого: A <: A|B, B <: A|B, чего Either не достигает.   -  person jack    schedule 08.03.2021
comment
Тип объединения также требует совпадения с образцом.   -  person Krzysztof Atłasik    schedule 08.03.2021
comment
@jack Если вы не знаете фактический тип возвращаемого значения, в конце концов вам придется сопоставить его, чтобы иметь возможность делать с ним что-либо значимое (кроме тривиальных вещей, таких как print или equals, но для этого вы могли бы просто используйте Any).   -  person Dima    schedule 08.03.2021
comment
Похоже, у вас есть проблема с дизайном в коде Spark, поскольку Scala 2 на самом деле не поддерживает типы объединения, ваш текущий подход обречен.   -  person Luis Miguel Mejía Suárez    schedule 08.03.2021


Ответы (1)


Он есть в готовящейся к выпуску Scala 3.

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

Как видно из этого сеанса Scastie.

person jwvh    schedule 07.03.2021
comment
Спасибо за обращение. В Scala 2.11 он по-прежнему не компилируется, есть ли способ добиться этого? - person jack; 08.03.2021