Early preview: syntax, standard library APIs, and tooling may change.

Core DataRecords

Records

Records group named fields into values. Updates preserve the original value; the compiler manages storage and sharing.

Record Literals and Fields

Declare a record's named fields and their types, then construct a value with field = value for every field. Use dot access such as player.score to read a field.

record Player {name: String, score: Int}


func main(args: List[String]) -> Void:
	player: Player = {
		name = "Ada",
		score = 91
	}
	print(player.name) -- prints: Ada
	print(player.score.to_string()) -- prints: 91

Record Update

{ old | field = value } returns a new record value.

next: Player = { player | score = player.score + 1 }

Generic Records

Records can take type parameters when the same named-field shape should carry different value types.

record Page[Item] {
	items: List[Item],
	next: Option[String]
}


names: Page[String] = {
	items = ["Ada", "Grace"],
	next = Some("page-2")
}

scores: Page[Int] = {
	items = [91, 100],
	next = None
}
-- names.items.get_or(0, "") == "Ada"
-- scores.items.get_or(1, 0) == 100
-- names.next == Some("page-2")

Value Semantics

A record update produces a new logical value. ARC and copy-on-write allow efficient storage reuse without changing that behavior.

record Score {points: Int}


func main(args: List[String]) -> Void:
	original: Score = {points = 10}
	updated: Score = { original | points = original.points + 5 }
	print(original.points.to_string()) -- 10
	print(updated.points.to_string()) -- 15

Fixed Records

A fixed record has a typechecking-level guarantee that its implementation does not allocate. Nested records and unions must also be fixed. Non-fixed records and unions are ineligible even when all their fields are scalar. Fixed and non-fixed records receive the same optimizations for identical bodies.

fixed record Point {x: Int, y: Int}


func main(args: List[String]) -> Void:
	original: Point = {x = 1, y = 2}
	moved: Point = { original | x = original.x + 10 }
	print(original.x.to_string()) -- 1
	print(moved.x.to_string()) -- 11

Example

player.brp
record Player {name: String, points: Int}


record Delta {points: Int}


pure func award(player: Player, event: Delta) -> Player:
	{ player | points = player.points + event.points }


func main(args: List[String]) -> Void:
	start: Player = {name = "Ada", points = 10}
	updated: Player = award(start, {points = 5})
	print(start.points) -- prints: 10
	print(updated.points) -- prints: 15

Try it

terminal
blorp run player.brp