Skip to content

Instantly share code, notes, and snippets.

@viktorklang
Last active August 30, 2015 12:55
Show Gist options
  • Save viktorklang/141420 to your computer and use it in GitHub Desktop.
Save viktorklang/141420 to your computer and use it in GitHub Desktop.
//isValid = predicate/constraint
abstract class Type[T](val isValid : (T) => boolean)
{
//X is the reference type
final protected[Type] case class X[T] (val value : T) {
override def toString = Type.this.getClass.getSimpleName + "(" + value + ")"
}
//Type is the alias for X[T] that we expose to the outside world
type Type = X[T]
//Apply and unapply for safe and secure instantiation and extraction
def apply(t : T) : Option[Type] = if(isValid(t)) Some(X(t)) else None
def unapply(v : Type) : Option[T] = if(v ne null) Some(v.value) else None
}
//Demonstrating creating a new value type based upon string with some simple constraints
object Zipcode extends Type[String](_.length > 0)
object City extends Type[String](_.length > 4)
//Employing the types on a simple struct-like type
case class Address(val zipcode : Zipcode.Type, val city : City.Type)
def main(a : Array[String]) : Unit = {
//Using a for-comprehension to assemble the type
val x = for {
z <- Zipcode("foo")
c <- City("bartown")
} yield Address(z,c)
//Using pattern-matching to extract the values
x map { case Address(z @ Zipcode(x),City(y)) => println(z +": " + x + " " + y)
case x => println(x)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment