Records and value semantics
ASPL 0.7.0 · Current release
Current 0.7.0 operations, host support, examples, and failure rules.
On this page
Named record types
ASPL 0.7.0 supports سجل/record on both hosts. Declare a record at file scope with named, typed fields separated by commas. A trailing comma is allowed. Record names are collected before field types resolve, so declaration order does not matter.
Records are nominal. Two declarations with identical fields are different types; identity belongs to the defining source module. The browser supports records in the entry file; user source modules require native execution.
Illustrative fragment
record Item { name: string, counts: list<i64> }Construction and field access
Construct a value using the type name and supply every field exactly once. Fields evaluate in written order. Unknown, duplicate, missing, or unit fields are source errors. Direct and indirect recursive record types, including recursion through lists or results, are rejected.
Postfix :: reads a field by value and chains with list indexes more tightly than arithmetic. User field names retain their spelling in Arabic, English, and mixed source. Only builtin result/error fields have supplied bilingual aliases. Parenthesize a record constructor directly in an if or while condition to distinguish its braces from the following block.
Illustrative fragment
let item = Item { name: "tools", counts: [2, 3] };
print(item::name);Copying and nested mutation
Assignments, arguments, and returns copy record values. A nested list or record in a copy also has value semantics. Change a field or indexed element only through a var root binding. A parameter, let binding, temporary, or result payload projection cannot be mutated. Copy a successful payload into a new mutable binding if you need to change it.
The complete example copies a parser state, changes its index and a nested token field, and verifies that the original still has its old values. It also carries a record in result<record-type>.
Execution: Browser and native · ASPL 0.7.0
- No prior knowledge is required to open and check it.
Input: No input lines are required.
record code { type_name: i64, text: string, line: i64, column: i64 }
record parser_state { codes: list<code>, index: i64 }
fn status_code(status: parser_state) -> code {
return status::codes[status::index];
}
fn start_main() -> i64 {
let increment: code = code { type_name: 1, text: "+" , line: 2, column: 7 };
if (increment::type_name not match 1) { return 1; }
if (increment::text not match "+") { return 2; }
if (increment::line not match 2) { return 3; }
if (increment::column not match 7) { return 4; }
var status: parser_state = parser_state { codes: [increment], index: 0 };
if (status_code(status)::text not match "+") { return 5; }
var moved: parser_state = status;
moved::index = 1;
if (status::index not match 0) { return 6; }
if (moved::index not match 1) { return 7; }
moved::codes[0]::column = 9;
if (status::codes[0]::column not match 7) { return 8; }
if (moved::codes[0]::column not match 9) { return 9; }
let exists: result<code> = success(increment);
if (exists::ok) {
if (exists::value::line not match 2) { return 10; }
} else {
return 11;
}
print("3 tokens");
return 0;
}
Expected outcomes
{
"browser": {
"check": "success",
"class": "success",
"output": "3 tokens",
"processStatus": 0
},
"native": {
"check": 0,
"status": 0,
"output": "3 tokens"
}
}Failures and scope
Whole-record equality is not supported. Field/type errors are source errors; an invalid nested list index traps with list-index-out-of-bounds, and reading the wrong result branch traps with wrong-result-branch. Records extend the historical MVP; their current behavior is independent of any C struct layout.
Read all record variants, lists, and recoverable results.