title: Union generic type without Either Scala
body: <p>This works fine:</p>
  <pre><code>def echo[A, B](a: A, b: B): A = ???
  </code></pre>
  <p>This is also fine:</p>
  <pre><code>def echo[A, B](a: A, b: B): B = ???
  </code></pre>
  <blockquote>
  <p>However, how do we achieve this to return either type A or B?</p>
  <pre><code>// error
  def echo[A, B](a: A, b: B): A|B = ???
  </code></pre>
  </blockquote>
  <p>Is it simply possible to have a <strong>union type</strong> of <strong>generic</strong> types <strong>A</strong> and <strong>B</strong>?
  Cheers.</p>
  <hr />
  <p><strong>UPDATE1</strong></p>
  <p><code>Either</code> is an option but not ideal, as it requires a <strong>pattern match</strong> when processing the returned result. Effectively, I want this: <code>A &lt;: A|B</code>, <code>B &lt;: A|B</code>, which <code>Either</code> does not achieve.</p>
  <p>Another extreme, I can do this, but type is too loose:</p>
  <pre><code>def echo[A, B](a: A, b: B): Any = ???
  </code></pre>
  <hr />
  <p><strong>UPDATE2</strong><br />
  Why I don't want <code>Either</code>?</p>
  <p>(Reason 2)</p>
  <p>The returned result would actually be a <code>Dataset</code> of <strong>Spark</strong>, which requires <code>Encoder</code> for any type that is not a subtype of <code>Product</code> (see <a href="https://stackoverflow.com/questions/36648128/how-to-store-custom-objects-in-dataset">this topic</a>).</p>
  <p>When calling this method many times, it ends up with too many <code>Either</code> wrapping each other, e.g. <code>Either[Either[Either[...]]]</code>. This requires too many encoders to be defined.</p>
  <p>So I'm actually doing this:</p>
  <pre><code>def echo[A, B](a: A, b: B): Dataset[A|B] = ???
  </code></pre>
  <p>If I do this it would require to have many different encoders due to <code>Either</code> type:</p>
  <pre><code>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...
  </code></pre>