Skip to content

Instantly share code, notes, and snippets.

@bishabosha
Created March 10, 2021 14:40
Show Gist options
  • Save bishabosha/5e081f3d74292fe07f3c12384e572de3 to your computer and use it in GitHub Desktop.
Save bishabosha/5e081f3d74292fe07f3c12384e572de3 to your computer and use it in GitHub Desktop.
Demonstrate using Opaque Type Aliases as evidence parameters to abstract over different storage
object Notarisation:
private case object Proven
opaque type Proof <: Singleton = Proven.type
given Proof = Proven
end Notarisation
import Notarisation.Proof
object Entities:
opaque type Entity[+T] = Long
object Entity:
def apply[T <: Proof](id: Long)(using T): Entity[T] = id
extension [T](e: Entity[T]) def id: Long = e
end Entities
import Entities.Entity
object Db:
trait Storage:
def newId: Long
def firstName(id: Long): String
def setFirstName(id: Long, firstName: String): Unit
def age(id: Long): Int
def setAge(id: Long, age: Int): Unit
end Db
object MyData:
opaque type Kind <: Singleton = Proof
object Kind:
opaque type Person <: Kind = Proof
// The only place you can create an Entity[Person]
def newPerson(firstName: String, age: Int)(using Db.Storage): Entity[Kind.Person] =
val id = summon[Db.Storage].newId
summon[Db.Storage].setFirstName(id, firstName)
summon[Db.Storage].setAge(id, age)
Entity(id)
extension (person: Entity[Kind.Person])
def firstName(using Db.Storage) = summon[Db.Storage].firstName(person.id)
def age(using Db.Storage) = summon[Db.Storage].age(person.id)
end MyData
given Db.Storage with
private var _id: Long = 0
private val _firstName: Array[String] = new Array(25)
private val _age: Array[Int] = new Array(25)
def newId: Long = { val id: Long = _id; _id += 1; id }
def firstName(id: Long): String = _firstName(id.toInt)
def setFirstName(id: Long, firstName: String): Unit = _firstName(id.toInt) = firstName
def age(id: Long): Int = _age(id.toInt)
def setAge(id: Long, age: Int): Unit = _age(id.toInt) = age
val Jamie = MyData.Kind.newPerson("Jamie", 24)
val Georgie = MyData.Kind.newPerson("Georgie", 21)
// val ?? = Entity[MyData.Kind.Person](56) // <- impossible
Jamie.firstName
Jamie.age
Georgie.firstName
Georgie.age
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment