Skip to content

Instantly share code, notes, and snippets.

@oscarduignan
Last active July 22, 2024 12:08
Show Gist options
  • Save oscarduignan/4fdf84d7089a8a49b65a1aec039ac677 to your computer and use it in GitHub Desktop.
Save oscarduignan/4fdf84d7089a8a49b65a1aec039ac677 to your computer and use it in GitHub Desktop.
Thinking about ways to model records in scala that can give compile time errors where required fields are missing
//> using scala 3
trait Key { type Value; trait Provided }
case class Person[+T] private(underlying: Map[Key, Any]):
def apply(k: Key): Option[k.Value] =
underlying.get(k).map(_.asInstanceOf[k.Value])
def set(k: Key, v: k.Value): Person[T & k.Provided] =
Person[T & k.Provided](underlying + (k -> v))
object Person:
object Params:
object Alias extends Key { type Value = String }
object Name extends Key { type Value = String }
object Age extends Key { type Value = Int }
def apply(): Person[Any] =
Person[Any](Map())
import Person.Params.*
val person = Person()
.set(Alias, "oscar")
.set(Age, 34)
person(Name)
person(Age)
def greet(person: Person[Name.Provided & Age.Provided]): String =
s"Hello ${person(Name).get.capitalize}, you are ${person(Age).get} years old!"
greet(person)
/*
./scala-cli records.sc
-- [E007] Type Mismatch Error: -------------------------------------------------
1 |greet(person)
| ^^^^^^
|Found: (person : Person[Person.Params.Alias.Provided & Person.Params.Age.Provided])
|Required: Person[Person.Params.Name.Provided & Person.Params.Age.Provided]
|
| longer explanation available when compiling with `-explain`
1 error found
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment