sigildocs

(sigil record)

(sigil record) - Dict-Backed Typed Values

Provides define-record for creating typed, extensible, immutable dict-backed values (the Clojure defrecord role). A record IS a real immutable dict — every dict operation works, arbitrary namespaced keys are allowed — yet it carries a unique type identity, declared fields (with optional defaults and type predicates), and single inheritance.

Records complement structs: define-struct is the opaque, fixed-slot, fast tier (the SRFI-9 / deftype role); define-record is the open data tier (the defrecord role). NOTE: this is deliberately NOT named define-record-type — SRFI-9 records are opaque and fixed, which in Sigil is define-struct.

Basic Usage

(import (sigil record))

(define-record buffer (name))
(define-record editor-buffer include: buffer (text default: "") (result))

(define e (editor-buffer name: "*editor*" text: "(+ 1 2)"))

(editor-buffer? e)       ; => #t
(buffer? e)              ; => #t   (inherited)
(dict? e)                ; => #t   (it IS a dict)
(editor-buffer-text e)   ; => "(+ 1 2)"  (accessor)
(buffer-name e)          ; => "*editor*" (parent accessor works)
(dict-ref e text:)       ; => "(+ 1 2)"  (dict ops work)

Immutable Typed Update

Pass an existing record as the first constructor argument to get a functionally-updated copy that preserves the type:

(define e2 (editor-buffer e result: "3"))
(editor-buffer? e2)          ; => #t
(editor-buffer-result e2)    ; => "3"
(editor-buffer-result e)     ; => #f  (original untouched)

Plain dict-set also preserves the type (the tag is a dict entry):

(editor-buffer? (dict-set e app/tag: "draft"))  ; => #t

The Type Tag Is Visible (by design)

An instance is a dict tagged with its type descriptor under the reserved key sigil/record-type:. The tag being a visible entry means records serialize/datafy carrying their own type, and a plain dict is never a record. Treat sigil/record-type: as reserved.

Inheritance

include: gives single inheritance: the child type's instances satisfy the parent predicate, inherit the parent's field defaults, and multimethods dispatching on the parent type apply (see (sigil method)). Works across modules — the parent is referenced through its constructor.

Field Options

(define-record point
  (x number? default: 0)   ; type predicate + default
  (y number? default: 0))

Type predicates generate procedure specs for the accessors.

IMPLEMENTATION NOTE — descriptor is a hand-rolled tagged vector, NOT a struct: using define-struct here would be a cross-module procedural macro use INSIDE the stdlib build session, which pre-fix release binaries miscompile (the phantom-module bug this feature's task fixed; see test-module-phantom-instantiation.sgl). Keeping the stdlib free of internal cross-module procedural-macro uses preserves the ability to build the monorepo with one-release-old binaries.

Exports

Create a record type descriptor.

fields is a list of field-name symbols; defaults an alist of (field-name . default-value); parent a record type or #f. Default values are evaluated by the CALLER (once, at type definition) — see the define-record notes on defaults.

(define point-type (make-record-type 'point '(x y) '((x . 0)) #f))
record-type?procedure

Test if a value is a record type descriptor.

(record-type? (record-type-of p))  ; => #t

Get the name of a record type as a symbol.

Get the record type's OWN declared field names (a list of symbols). Inherited fields are on the parent; walk record-type-parent.

Get the record type's OWN field defaults as an alist.

Get the parent record type, or #f if none.

record?procedure

Test if a value is a record instance (a dict tagged with a record type descriptor under sigil/record-type:).

(record? (point x: 1))  ; => #t
(record? #{})           ; => #f  (a plain dict is not a record)

Get the record type descriptor of an instance, or #f.

record-isa?procedure

Test if record type t is ancestor or inherits from it.

record-of?procedure

Test if x is an instance of record type rt (or a subtype).

(record-of? e %editor-buffer--type)  ; instance-of, chain-aware
record-makeprocedure

Construct a record instance of type rt from a keyword-value plist, e.g. (record-make point-type (list x: 1 y: 2)). Declared field defaults (own + inherited) are filled first.

Internal (referenced by define-record expansions): constructor body shared by all record constructors. If the first argument is already an instance of rt (or a subtype), copy-construct — apply the keyword updates functionally, preserving its type and any extra keys. A record/dict of the WRONG type as first argument is a clear error, not a keyword.

Internal: extract the record type descriptor attached to a define-record constructor (used to resolve include: parents, including across modules).

(No description)