Skip to content

Instantly share code, notes, and snippets.

@jcarver989
Created February 13, 2014 05:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jcarver989/2fbb1ee926f57373aac5 to your computer and use it in GitHub Desktop.
Save jcarver989/2fbb1ee926f57373aac5 to your computer and use it in GitHub Desktop.
// let's us tag primitives with made up types
type Tagged[T] = { type Tag = T }
// have to declare our type annotations for use below
trait BizoIdTag
trait PartnerIdTag
trait AppNexusIdTag
// afaik effectively this treats the lhs (ex BizoId) of the alias as a subclass
// of the primitive, only with the added type
type BizoId = String with Tagged[BizoIdTag]
type PartnerId = Long with Tagged[PartnerIdTag]
type AppNexusId = Long with Tagged[AppNexusIdTag]
// Spark on Scala 2.10 now, which means we can use value classes
// afaik at runtime we don't allocate new objects at all
implicit class TaggedString(val data: String) extends AnyVal {
// looks scary, but this cast actually can't fail
def bizoId = data.asInstanceOf[BizoId]
}
implicit class TaggedLong(val data: Long) extends AnyVal {
def partnerId = {
require(data >= 1) // oooooo validation!
data.asInstanceOf[PartnerId]
}
def appNexusId = data.asInstanceOf[AppNexusId]
}
def doSomething(bizoId: BizoId, appNexusId: AppNexusId): String = {
"Hello World"
}
doSomething("129IDKAJDf".bizoId, 12345.appNexusId) // yay!
doSomething("129IDKAJDf".bizoId, 12345.partnerId) // compiler Error!
@bearrito
Copy link

bearrito commented Mar 2, 2014

Playing around with these techniques gives me some errors.

I have

object DomainTypes {
  type Tagged[T] = { type Tag = T }
  trait DeviceIdTag
  type DeviceId = Int with Tagged[DeviceIdTag]

  implicit class TaggedInt(val data: Int) extends AnyVal {

     def deviceId = {
      require(data >= 1)
      data.asInstanceOf[DeviceId]
    }
  }
}

That gives me this stacktrace.

[error] type mismatch;
[error]  found   : Double
[error]  required: AnyRef
[error] Note: an implicit exists from scala.Double => java.lang.Double, but
[error] methods inherited from Object are rendered ambiguous.  This is to avoid
[error] a blanket implicit which would convert any scala.Double to any AnyRef.
[error] You may wish to use a type ascription: `x: java.lang.Double`.
[error] one error found
[error] (compile:compile) Compilation failed

Edit: I left out one important piece.

I then try and use it like :

 case class DeviceIdHolder(odeviceId:DeviceId)

Have you ever seen anything like this? In any case, nice write up . Thanks!

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