2

I am using Rex Kerr's variant of Miles Sabin's idea for implementing unboxed union types in Scala. I have the following class:

class Foo[T] {
  trait Contr[-A] {}
  type Union[A,B] = {type Check[Z] = Contr[Contr[Z]] <:< Contr[Contr[A] with Contr[B]]}

  def foo[U: Union[T,Foo[T]]#Check](x:U) = x match {
    case _: Foo[T]       => println("x is a Foo[T]")
    case _: T @unchecked => println("x is a T")
  }
}

This allows the following:

val aux = new Foo[Int]
aux.foo(aux)   // prints "x is a Foo[T]"
aux.foo(42)    // prints "x is a T"
aux.foo("bar") // does not compile

However:

val bar = new Foo[Foo[Int]]
bar.foo(bar) // OK: prints "x is a Foo[T]"
bar.foo(aux) // Not OK: prints "x is a Foo[T]"

Is there a way to fix this, and maybe also eliminate the @unchecked?

EDIT I think the Union type, for this particular example, can be simplified to:

type Union[Z] = Contr[Contr[Z]] <:< Contr[Contr[T] with Contr[Foo[T]]]

and then the foo function can be:

def foo[U: Union](x:U) = ...

This makes the code simpler. However, the issue remains.

Community
  • 1
  • 1
Eduardo
  • 8,362
  • 6
  • 38
  • 72

1 Answers1

0

I have come up with the following, which seems to work, and is closer to my real use case:

import scala.reflect.runtime.universe._

case class Foo[T](z:T)(implicit tt:TypeTag[T], ft:TypeTag[Foo[T]]) {

  trait Contr[-A]
  type Union[Z] = Contr[Contr[Z]] <:< Contr[Contr[T] with Contr[Foo[T]]]

  def foo[U: Union](x:U)(implicit tu:TypeTag[U]):T = tu.tpe match {
    case t if t =:= tt.tpe => x.asInstanceOf[T]
    case t if t =:= ft.tpe => x.asInstanceOf[Foo[T]].z
  }

}

Now, the following works well:

val aux    = new Foo[Int](42)
val bar    = new Foo[Int](7)
val foobar = new Foo[Foo[Int]](bar)

println(aux.foo(aux))       // 42
println(aux.foo(1))         // 1
println(foobar.foo(aux))    // Foo(42)
println(foobar.foo(foobar)) // Foo(7)

I would be nice to get rid of the x.asInstanceOf, though.

Eduardo
  • 8,362
  • 6
  • 38
  • 72