Instantly share code, notes, and snippets.

Embed
What would you like to do?
Unboxed newtype in Scala?
// 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
}
@retronym

This comment has been minimized.

Show comment
Hide comment
@retronym

retronym commented Sep 21, 2011

Neat!

@iron9light

This comment has been minimized.

Show comment
Hide comment
@iron9light

iron9light Sep 21, 2011

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.

iron9light commented Sep 21, 2011

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

This comment has been minimized.

Show comment
Hide comment
@retronym

retronym Sep 21, 2011

With a few type aliases for good measure: https://gist.github.com/8fe2c19e4431e817015b

retronym commented Sep 21, 2011

With a few type aliases for good measure: https://gist.github.com/8fe2c19e4431e817015b

@milessabin

This comment has been minimized.

Show comment
Hide comment
@milessabin

milessabin Sep 21, 2011

@retronym Yup, I like the look of those.

Owner

milessabin commented Sep 21, 2011

@retronym Yup, I like the look of those.

@soc

This comment has been minimized.

Show comment
Hide comment
@soc

soc Sep 22, 2011

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 commented Sep 22, 2011

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?

@milessabin

This comment has been minimized.

Show comment
Hide comment
@milessabin

milessabin Sep 22, 2011

@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, tagUser+tagCheckin compiles and has the value 36 : Int ... definitely not what you want for UoM.

Owner

milessabin commented Sep 22, 2011

@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, tagUser+tagCheckin compiles and has the value 36 : Int ... definitely not what you want for UoM.

@adamw

This comment has been minimized.

Show comment
Hide comment
@adamw

adamw Nov 25, 2015

I need type tagging only (without shapeless or scalaz) in some projects so I published it as a one-class artifact, if anybody would find that useful as well: https://github.com/softwaremill/scala-common

adamw commented Nov 25, 2015

I need type tagging only (without shapeless or scalaz) in some projects so I published it as a one-class artifact, if anybody would find that useful as well: https://github.com/softwaremill/scala-common

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment