Records
Calcit provides Records as a way to define structured data types with named fields, similar to structs in other languages. Records are implemented using tuples internally and support polymorphism through methods.
Creating Records
Using new-record
Create a record type using the new-record function:
new-record :Point :x :y
Using %{} Macro
Create a record instance with the %{} macro:
let
Point $ new-record :Point :x :y
p $ %{} Point
:x 1
:y 2
, p
Record Operations
Accessing Fields
let
Point $ new-record :Point :x :y
p $ %{} Point
:x 1
:y 2
&record:get p :x
; => 1
Updating Fields
let
Point $ new-record :Point :x :y
p $ %{} Point
:x 1
:y 2
p2 $ record-with p
:x 10
; p2 is a new record with :x = 10, :y unchanged
Setting Single Field
&record:assoc p :x 100
; => new record with updated :x
Record with Methods
Records can have methods that operate on the record data:
defrecord! Rectangle
:width 0
:height 0
:area $ fn (self)
* (&record:get self :width)
(&record:get self :height)
:scale $ fn (self factor)
record-with self
:width $ * (&record:get self :width) factor
:height $ * (&record:get self :height) factor
let
rect $ %{} Rectangle
:width 10
:height 5
println $ .area rect
; => 50
Type Checking
; Check if value is a record
record? p
; => true
; Check record class
&record:class p
; => returns the record class
; Check if record matches a class
&record:matches? p Point
; => true
Converting Records
To Map
&record:to-map p
; => {} (:x 1) (:y 2)
From Map
&record:from-map Point $ {} (:x 1) (:y 2)
; => record with x=1, y=2
Pattern Matching
Use record-match to pattern match on record types:
let
Circle $ new-record :Circle :radius
Square $ new-record :Square :side
shape $ %{} Circle
:radius 5
record-match shape
Circle c $ * 3.14 (* (&record:get c :radius) (&record:get c :radius))
Square s $ * (&record:get s :side) (&record:get s :side)
_ _ nil
Record Class Operations
Getting Record Name
&record:get-name Point
; => :Point
Extending Records
&record:extend-as p :Point3D
:z 0
Changing Class
&record:with-class p NewClass
Record vs Struct
- Records: Runtime data structures with fields and optional methods
- Structs: Type definitions used for compile-time type checking
let
Person $ defstruct Person
:name :string
:age :number
%{} Person
:name |Alice
:age 30
Common Use Cases
Configuration Objects
new-record :Config
:host
:port
:debug
:log-level
let
config $ %{} Config
:port 3000
println $ &record:get config :port
; => 3000
Domain Models
new-record :Product
:id
:name
:price
:discount
let
product $ %{} Product
:id |P001
:name |Widget
:price 100
:discount 0.9
println $ * (&record:get product :price) (&record:get product :discount)
; => 90
Type Annotations
let
User $ new-record :User
:name
:age
:email
defn get-user-name (user)
hint-fn $ return-type :string
assert-type user $ :: :record User
&record:get user :name
get-user-name $ %{} User
:name |John
:age 30
:email |john@example.com
Performance Notes
- Records are immutable - updates create new records
- Field access is O(1)
- Records share structure when possible
- Use
record-withfor multiple field updates to minimize copying