secret
Last active

Unboxed newtype in Scala?

  • Download Gist
gistfile1.scala
Scala
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
// Compile with -optimize to eliminate boxing/unboxing in specialized
// tag methods.
 
class User
class Checkin
type Tagged[U] = { type Tag = U }
type @@[T, U] = T with Tagged[U] // Thanks to @retronym for suggesting this type alias
class Tagger[U] {
def apply[T](t : T) : T @@ U = t.asInstanceOf[T @@ U]
}
def tag[U] = new Tagger[U]
 
// Manual specialization needed here ... specializing apply above doesn't help
def tag[U](i : Int) : Int @@ U = i.asInstanceOf[Int @@ U]
def tag[U](l : Long) : Long @@ U = l.asInstanceOf[Long @@ U]
def tag[U](d : Double) : Double @@ U = d.asInstanceOf[Double @@ U]
 
def fetch[A](id: Int @@ A): A = null.asInstanceOf[A]
 
def main(args: Array[String]): Unit = {
val id = tag[Checkin](10)
fetch[Checkin](id) // Compiles
fetch[User](id) // Does not compile
val ids = tag[User](1) :: tag[User](2) :: tag[User](3) :: Nil
val users : List[(Int @@ User)] = ids // Compiles
val checkins : List[Int @@ Checkin] = ids // Does not compile
}
class Gram
class KiloGram
implicit def convert(a: Int with Tagged[KiloGram]): Int with Tagged[Gram] = (a * 1000).asInstanceOf[Int with Tagged[Gram]]
implicit def convert2(b: Int with Tagged[Gram]): Int with Tagged[KiloGram] = (a/1000).asInstanceOf[Int with Tagged[KiloGram]]

It's not useful.

@retronym Yup, I like the look of those.

Brilliant. I'm just researching how units of measurements can be implemented in Scala. Would it be possible to make this also support unit conversions, e. g. Length * Time == Speed and comparable things?

@soc No I don't think it's up to that. The main problem is that eg. Int @@ T <: Int for any T, so the usual arithmetic operators are applicable (via simple subtype conformance of their arguments) and will have their ordinary result type (ie. Int). So, in particular, tag[User](23)+tag[Checkin](13) compiles and has the value 36 : Int ... definitely not what you want for UoM.

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.