42.type: 
Literal-based singleton types in Scala 
@folone @xeno_by @retronym @adriaanm @extempore2
About me: 
@folone 
likes types* 
*same reasons why @propensive does in 
his “Batshit crazy algebra with types” talk
Examples
1. Records
val book = ("author" ->> "Benjamin Pierce") :: 
("title" ->> "TAPL") :: 
("id" ->> 262162091) :: 
("price" ->> 44.11) :: 
HNil 
! 
scala> book("author") // Note the result type 
res0: String = Benjamin Pierce 
! 
scala> book("id") // Note the result type 
res1: Int = 262162091
trait Assoc[K] { type V ; val v: V } 
defined trait Assoc 
! 
def mkAssoc[K, V0](k: K,v0: V0): 
Assoc[k.type] { type V = V0 } = 
new Assoc[k.type] {type V = V0 ; val v = v0} 
mkAssoc: [K, V0](k: K, v: V0)Assoc[k.type]{type V = V0} 
! 
def lookup[K](k: K) 
(implicit a: Assoc[k.type]): a.V = a.v 
lookup: [K](k: K)(implicit assoc: Assoc[k.type])assoc.V
> implicit def firstAssoc = mkAssoc(1, "Panda!") 
firstAssoc: Assoc[1.type]{type V = String} 
! 
> implicit def ageAssoc = mkAssoc("Age", 3) 
ageAssoc: Assoc["Age".type]{type V = Int} 
! 
> implicit def nmAssoc = mkAssoc(“Name", “Jane”) 
nmAssoc: Assoc["Name".type]{type V = String} 
scala> lookup(1) 
res0: String = Panda! 
scala> lookup("Age") 
res1: Int = 3 
scala> lookup("Name") 
res2: String = Jane
2. Residue
case class Residue[N <: Int: SingleInhabitant](n: Long){ 
lhs => 
def +(rhs: Residue[N]): Residue[N] = 
Residue((lhs.n + rhs.n) % inhabitant[N]) 
}
scala> Residue[15](15) + Residue[13](20) 
<console>:10: error: type mismatch; 
found : Residue[13.type] 
required: Residue[15.type] 
Residue[15](15) + Residue[13](20) 
^ 
scala> Residue[13](15) + Residue[13](20) 
res1: Residue[13.type] = Residue(9)
3. Ranged
class Ranged[From <: Int : SingleInhabitant, 
To <: Int : SingleInhabitant] { 
def sample = { 
val rnd = new scala.util.Random 
val from = inhabitant[From] 
val to = inhabitant[To] 
(from + rnd.nextInt(to - from + 1)) 
} 
}
scala> val range = new Ranged[10, 20] 
range: Ranged[10.type,20.type] = 
Ranged@78c22d25 
! 
scala> range.sample 
res0: Int = 13 
! 
scala> range.sample 
res1: Int = 11
Consistency
Here’s what you 
can do in Scala 
scala> val x = "panda!" 
x: String = panda! 
! 
scala> val t: x.type = x 
t: x.type = panda! 
! 
scala> final val k = "panda!" 
k: String("panda!") = panda!
Here’s what you 
cannot 
scala> val t: "panda!".type = "panda!" 
<console>:1: error: identifier expected 
but string literal found. 
val t: "panda!".type = "panda!" 
^
With 42.type 
scala> val t: "panda!".type = "panda!" 
t: "panda!".type = panda!
Even more 
scala> val x = 42 
x: Int = 42 
! 
scala> val t: x.type = 42 
<console>:8: error: type mismatch; 
found : x.type (with underlying type Int) 
required: AnyRef 
val t: x.type = 42 
^ 
scala> val workaround = Witness(42) 
workaround: shapeless.Witness{type T = Int(42)} = fresh$macro$3$1@35b45d3f 
! 
scala> val t: workaround.T = 42 
t: workaround.T = 42
Solution with 42.type 
scala> val t: 42.type = 42 
t: 42.type = 42 
! 
! 
! 
scala> val t: 42 = 42 
t: 42.type = 42 
Or even
42: Literal-based singleton types in Scala
Before 
SimpleType ::= Path ‘.’ type 
A singleton type is of the form p.type, 
where p is a path pointing to a value 
expected to conform to scala.AnyRef.
After 
SimpleType ::= Path ‘.’ type 
| Literal [‘.’ type]
4.
State of deptypes Scala 
“Scala vs Idris: Dependent 
Types, Now and in the Future”* 
*Edwin Brady & Miles Sabin, Strange Loop 2013
How can we 
make it better? 
Well, we can try. 
Scala + Z3
scala> import z3.scala._, z3.scala.dsl._ 
import z3.scala._ 
import z3.scala.dsl._
scala> findAll((x: Val[Int]) => x > 23 && x < 42).toList 
res0: List[Int] = List(24, 25, 26, 27, 28, 29, 30, 31, 
32, 33, 34, 35, 36, 37, 38, 39, 40, 41)
((x: Val[Int]) => x > 23 && x < 42)
((x: Int) => x > 23 && x < 42)
((x: Int) => x > 23 && x < 42).type
val magic: ((x: Int) => x > 23 && x < 42).type = 30
val magic: ((x: Int) => x > 23 && x < 42).type = 30 
val x: 42 = 42 val x: ((x: Int) => x == 42).type = 42
val magic: ((x: Int) => x > 23 && x < 42).type = 30 
val x: 42 = 42 val x: ((x: Int) => x == 42).type = 42 
val x: Int = 42 val x: ((x: Int) => x).type = 42
bit.ly/42_type
Credits: 
this thing would not be possible without: 
@xeno_by, @retronym, @adriaanm, 
and initial impl by @paulp 
Scala Z3 bindings: LARA@EPFL 
Z3: Microsoft research 
slides, illustrations: @killnicole
Thanks. Questions? 
- Contributing to Scala compiler 
- Type-level programming 
- Working/hackertime at SoundCloud 
Ask me about:

42.type: Literal-based Singleton types

  • 1.
    42.type: Literal-based singletontypes in Scala @folone @xeno_by @retronym @adriaanm @extempore2
  • 2.
    About me: @folone likes types* *same reasons why @propensive does in his “Batshit crazy algebra with types” talk
  • 4.
  • 5.
  • 6.
    val book =("author" ->> "Benjamin Pierce") :: ("title" ->> "TAPL") :: ("id" ->> 262162091) :: ("price" ->> 44.11) :: HNil ! scala> book("author") // Note the result type res0: String = Benjamin Pierce ! scala> book("id") // Note the result type res1: Int = 262162091
  • 7.
    trait Assoc[K] {type V ; val v: V } defined trait Assoc ! def mkAssoc[K, V0](k: K,v0: V0): Assoc[k.type] { type V = V0 } = new Assoc[k.type] {type V = V0 ; val v = v0} mkAssoc: [K, V0](k: K, v: V0)Assoc[k.type]{type V = V0} ! def lookup[K](k: K) (implicit a: Assoc[k.type]): a.V = a.v lookup: [K](k: K)(implicit assoc: Assoc[k.type])assoc.V
  • 8.
    > implicit deffirstAssoc = mkAssoc(1, "Panda!") firstAssoc: Assoc[1.type]{type V = String} ! > implicit def ageAssoc = mkAssoc("Age", 3) ageAssoc: Assoc["Age".type]{type V = Int} ! > implicit def nmAssoc = mkAssoc(“Name", “Jane”) nmAssoc: Assoc["Name".type]{type V = String} scala> lookup(1) res0: String = Panda! scala> lookup("Age") res1: Int = 3 scala> lookup("Name") res2: String = Jane
  • 9.
  • 10.
    case class Residue[N<: Int: SingleInhabitant](n: Long){ lhs => def +(rhs: Residue[N]): Residue[N] = Residue((lhs.n + rhs.n) % inhabitant[N]) }
  • 11.
    scala> Residue[15](15) +Residue[13](20) <console>:10: error: type mismatch; found : Residue[13.type] required: Residue[15.type] Residue[15](15) + Residue[13](20) ^ scala> Residue[13](15) + Residue[13](20) res1: Residue[13.type] = Residue(9)
  • 12.
  • 13.
    class Ranged[From <:Int : SingleInhabitant, To <: Int : SingleInhabitant] { def sample = { val rnd = new scala.util.Random val from = inhabitant[From] val to = inhabitant[To] (from + rnd.nextInt(to - from + 1)) } }
  • 14.
    scala> val range= new Ranged[10, 20] range: Ranged[10.type,20.type] = Ranged@78c22d25 ! scala> range.sample res0: Int = 13 ! scala> range.sample res1: Int = 11
  • 15.
  • 16.
    Here’s what you can do in Scala scala> val x = "panda!" x: String = panda! ! scala> val t: x.type = x t: x.type = panda! ! scala> final val k = "panda!" k: String("panda!") = panda!
  • 17.
    Here’s what you cannot scala> val t: "panda!".type = "panda!" <console>:1: error: identifier expected but string literal found. val t: "panda!".type = "panda!" ^
  • 18.
    With 42.type scala>val t: "panda!".type = "panda!" t: "panda!".type = panda!
  • 19.
    Even more scala>val x = 42 x: Int = 42 ! scala> val t: x.type = 42 <console>:8: error: type mismatch; found : x.type (with underlying type Int) required: AnyRef val t: x.type = 42 ^ scala> val workaround = Witness(42) workaround: shapeless.Witness{type T = Int(42)} = fresh$macro$3$1@35b45d3f ! scala> val t: workaround.T = 42 t: workaround.T = 42
  • 20.
    Solution with 42.type scala> val t: 42.type = 42 t: 42.type = 42 ! ! ! scala> val t: 42 = 42 t: 42.type = 42 Or even
  • 21.
  • 22.
    Before SimpleType ::=Path ‘.’ type A singleton type is of the form p.type, where p is a path pointing to a value expected to conform to scala.AnyRef.
  • 23.
    After SimpleType ::=Path ‘.’ type | Literal [‘.’ type]
  • 24.
  • 25.
    State of deptypesScala “Scala vs Idris: Dependent Types, Now and in the Future”* *Edwin Brady & Miles Sabin, Strange Loop 2013
  • 26.
    How can we make it better? Well, we can try. Scala + Z3
  • 27.
    scala> import z3.scala._,z3.scala.dsl._ import z3.scala._ import z3.scala.dsl._
  • 28.
    scala> findAll((x: Val[Int])=> x > 23 && x < 42).toList res0: List[Int] = List(24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41)
  • 29.
    ((x: Val[Int]) =>x > 23 && x < 42)
  • 30.
    ((x: Int) =>x > 23 && x < 42)
  • 31.
    ((x: Int) =>x > 23 && x < 42).type
  • 32.
    val magic: ((x:Int) => x > 23 && x < 42).type = 30
  • 33.
    val magic: ((x:Int) => x > 23 && x < 42).type = 30 val x: 42 = 42 val x: ((x: Int) => x == 42).type = 42
  • 34.
    val magic: ((x:Int) => x > 23 && x < 42).type = 30 val x: 42 = 42 val x: ((x: Int) => x == 42).type = 42 val x: Int = 42 val x: ((x: Int) => x).type = 42
  • 36.
  • 37.
    Credits: this thingwould not be possible without: @xeno_by, @retronym, @adriaanm, and initial impl by @paulp Scala Z3 bindings: LARA@EPFL Z3: Microsoft research slides, illustrations: @killnicole
  • 39.
    Thanks. Questions? -Contributing to Scala compiler - Type-level programming - Working/hackertime at SoundCloud Ask me about: