Generic records for Scala. Record types have the form
Field[Label1, Value1] with ... with Field[LabelN, ValueN]
where Field
is invariant in its first argument and covariant in the second.
Add Sager to your dependencies
libraryDependencies += "com.github.mvv.sager" %% "sager" % "0.2-M1"
To construct a record, use
import com.github.mvv.sager._
// Label types
trait Foo
trait Bar
trait Baz
val r = Field[Foo]("foo").add[Bar](123).add[Baz](Vector.empty[Double])
// val r: Field[Foo,String] with Field[Bar,Int] with Field[Baz,Vector[Double]]
Record types are polymorthic in expected ways:
// All of the following implicit searches succeed
implicitly[r.type <:< Field[Bar,Int] with Field[Foo,String]]
implicitly[r.type <:< Field[Baz,Seq[Double]]]
Accessing and modifying fields is simple:
val bar = r.get[Bar]
// val bar: Int = 123
val newBar = r.add[Bar](false).get[Bar]
// val newBar: Boolean = false
// You can omit the `: Int` annotation in Scala 3
val updatedBar = r.update[Bar]((_: Int) > 100).get[Bar]
// val updatedBar: Boolean = true
// Same thing, but more inference-friendly
val mappedBar = r.field[Bar].map(_ > 100).get[Bar]
// val mappedBar: Boolean = true
val r1 = r.remove[Bar]
// val r1: Field[Foo,String] with Field[Baz,Vector[Double]]