Extensible Records
Record Construction
In record4s, %
is used for a signature of extensible records. First, import %
to use
them.
import com.github.tarao.record4s.%
Then use %
as a constructor to instantiate a record.
val person = %(name = "tarao", age = 3)
// person: % {
// val name: String
// val age: Int
// } = %(name = tarao, age = 3)
In addition, you can omit field names when they are the same as variable names.
val name = "tarao"
// name: String = "tarao"
val age = 3
// age: Int = 3
%(name, age)
// res0: % {
// val name: String
// val age: Int
// } = %(name = tarao, age = 3)
Field Access
You can access to fields in records in a type-safe manner.
person.name
// res1: String = "tarao"
person.age
// res2: Int = 3
Accessing an undefined field is statically rejected.
person.email
// error:
// value email is not a member of com.github.tarao.record4s.%{val name: String; val age: Int} - did you mean person.wait?
Extending Records
You can extend records by +
or updated
.
val personWithEmail = person + (email = "tarao@example.com")
// personWithEmail: % {
// val name: String
// val age: Int
// val email: String
// } = %(name = tarao, age = 3, email = tarao@example.com)
It is possible to extend a record with multiple fields.
person + (email = "tarao@example.com", occupation = "engineer")
// res4: % {
// val name: String
// val age: Int
// val email: String
// val occupation: String
// } = %(name = tarao, age = 3, email = tarao@example.com, occupation = engineer)
Record Concatenation
You can concatenate two records by ++
or concat
.
val email = %(email = "tarao@example.com")
// email: % {
// val email: String
// } = %(email = tarao@example.com)
person ++ email
// res5: % {
// val name: String
// val age: Int
// val email: String
// } = %(name = tarao, age = 3, email = tarao@example.com)
Field Update
If you extend a record by existing field label, then the field value is overridden. The type of the field may differ from the existing one.
person + (age = person.age + 1)
// res6: % {
// val name: String
// val age: Int
// } = %(name = tarao, age = 4)
personWithEmail + (email = %(user = "tarao", domain = "example.com"))
// res7: % {
// val name: String
// val age: Int
// val email: % {
// val user: String
// val domain: String
// }
// } = %(name = tarao, age = 3, email = %(user = tarao, domain = example.com))
This also applies to concatenation. The semantics is that "the latter one wins" like duplicate keys in Map construction or concatenation.