Apocalisp has a great series on Type Level Programming with Scala. At some point the question came up whether it is possible to determine equality of types at run time by having the compiler generate types representing true and false respectively. Here is what I came up with.
trait True { type t = True } trait False { type t = False } case class Equality[A] { def check(x: A)(implicit t: True) = t def check[B](x: B)(implicit f: False) = f } object Equality { def witness[T] = null.asInstanceOf[T] implicit val t: True = null implicit val f: False = null } // Usage: import Equality._ val test1 = Equality[List[Boolean]] check witness[List[Boolean]] implicitly[test1.t =:= True] // Does not compile since tt is True // implicitly[test1.t =:= False] val test2 = Equality[Nothing] check witness[AnyRef] // Does not compile since ft is False // implicitly[test2.t =:= True] implicitly[test2.t =:= False]
Admittedly this is very hacky. For the time being I don’t see how to further clean this up. Anyone?
[…] This post was mentioned on Twitter by Planet Scala, Planet Lang. Planet Lang said: [Scala] Type Level Programming: Equality: Apocalisp has a great series on Type Level Programming with Scala. At so… http://bit.ly/9YaHCt […]
An alternative solution is:
object typeeq {
trait True
trait False
class AreEqual[T1, T2, RT]
def value[T] = null.asInstanceOf[T]
implicit def areEqual[T] = new AreEqual[T, T, True]
def teq[T1, T2, RT](v1 : T1, v2 : T2)(implicit e : AreEqual[T1, T2, RT] =
new AreEqual[T1, T2, False]) = value[RT]
}
Usage:
scala> import typeeq._
import typeeq._
scala> teq(value[Int], value[Int])
res0: typeeq.True = null
scala> teq(value[Int], value[Double])
res1: typeeq.False = null
Not exactly I think. Solutions involving implicits seem to make it impossible to extract the desired static type at compile time. For your solution the following fails:
That’s because tv.type is not the same type as True. Use tv.t like in your original example and it works.
Relying on method overloading, like you do in your original example, doesn’t buy you anything compared to using implicits. In fact, it’s worse since you can’t propagate overload resolution control. For example:
scala> def check[T1, T2] = Equality[T1] check witness[T2]
check: [T1,T2]types.False
To my knowledge, there is unfortunately no way to implement type level equality checks in Scala.
I see, nice approach!
I tried to refine this a bit. Now the equality check returns a value representing the result of the equality check. This value can at the same time be used to project out the type level encoding of the equality check result.
usage: