[ AxiomCore · Documentation ]
Values, types and operators
Acore literals, built-in types, type expressions, operators, precedence and null handling, checked with Axiom CLI 0.149.1.
This page lists the values, types and operators you can use in Acore. Acore has
two expression grammars: the general evaluator used by general modules and
property values, and the checked expression grammar used by backend
pure fn bodies, managed blocks and Acore UI. Each section says which one it
covers. Examples were evaluated with axiom eval or checked with axiom check
from CLI 0.149.1.
Values in general modules
| Family | Source form | Notes |
|---|---|---|
| Null | null | The only null value. A property whose value is null is left out of rendered output. |
| Boolean | true, false | |
| Integer | 42, -7 | Signed 64-bit. Overflow is an error (Integer overflow). |
| Float | 3.14, -0.5 | 64-bit. A whole float such as 7.0 renders as 7. |
| String | "hello" | See Strings and numbers for the other string forms. |
| List | [1, 2], Listing { 1 2 } | |
| Object | { key = value }, name { ... } | Named properties and evaluated keys. |
| Mapping | Mapping { ["key"] = value } | Evaluated key and value entries. |
| Function | (x) -> x + 1 | A lambda with lexical capture. Functions are left out of rendered output. |
| Set, Map, Regex, Bytes | Library values | Members exist, but 0.149.1 binds no source constructor. See Standard library. |
| Duration, DataSize | Duration { value = 5 unit = "s" } | Unit-aware classes from the base module. |
Types in general modules
name: String = "tasks"
attempts: Int = 3
enabled: Boolean = true
ratio: Number = 1.5
description: String? = null
identifier: String | Int = "task-1"
mode: "audit" | "strict" = "audit"
tags: Listing<String> = Listing { "alpha" }
sampleRate: Float(this >= 0.0 && this <= 1.0) = 0.5
handler: (String, Int) -> Boolean = (s, i) -> true| Type | Accepts |
|---|---|
Int | Integers only. 1.0 is a type mismatch. |
Float | Floats only. 1 is a type mismatch; use Number for either. |
Number | Integers and floats |
String, Boolean, Null | The matching literal |
Listing, Listing<T> | Lists. A type argument is checked for each element. |
Mapping | Mappings and maps |
Dynamic | Plain objects |
Object | Plain and typed objects |
Any | Every value |
T? | T or null |
A | B | Either type |
"a" | "b" | One of the string literals |
T(constraint) | T, where the constraint expression on this is true |
(A, B) -> R | A function type. Parameter types are not checked when a lambda is called. |
Rules verified in 0.149.1:
- A declared type and its constraints are checked on the property's value.
x: Int(this > 0) = -5fails withType mismatch. typealias Mode = "audit" | "strict"is accepted, but a property typedModeis not checked against the literals. Write the union inline when you need the check.- A typed object such as
Base { port = "x" }does not re-check an overridden property against the class's declared type or constraint. A class property with no default must still be set. Profile validators for backend, UI and database sources remain authoritative. - Constraints validate authored values during evaluation. They are not server-side authorization rules.
Types in backend and UI declarations
Backend models use these types. Field constraints such as
String(minLength: 1) are listed in Validation.
| Type | Notes |
|---|---|
String, Bool, Bytes, DateTime, Json, Void | Boolean and Int are not backend types. |
Int32, Int64, Float32, Float64 | Sized numbers. Int64 stays exact on the backend. |
List<T>, Map<K, V> | Collections. Values are written as bracketed lists and {key: value} records. |
Optional<T>, T? | An optional value |
Models.Name, Entities.name | A model or promoted entity |
Acore UI has its own portable types, such as Int and Bool, and keeps
integers within the safe JavaScript range. See Acore UI.
Operators in general modules
From lowest to highest binding precedence. All binary operators are left
associative except **.
| Precedence | Operators | Meaning |
|---|---|---|
| 1 | |> | Parsed, but not evaluated in 0.149.1: it fails with Type mismatch in math. Call the function instead. |
| 2 | || | Short-circuit OR on Booleans |
| 3 | && | Short-circuit AND on Booleans |
| 4 | ==, != | Equality for any two values. 1 == 1.0 is true. |
| 5 | <, <=, >, >= | Numbers only. Comparing strings fails (Invalid string op). |
| 6 | ?? | The right operand when the left is null. The right side is evaluated only when needed. |
| 7 | +, - | Numbers. + also joins two strings; 1 + "x" is a type mismatch. |
| 8 | *, / | Numbers. / always returns a float: 7 / 2 is 3.5 and 6 / 2 is 3.0. |
| 9 | ** | Power, right associative: 2 ** 3 ** 2 is 512. A negative exponent returns a float. |
Unary - negates a number and ! negates a Boolean. Mixing an integer and a
float promotes to float. Integer +, -, * and ** fail on overflow, and
integer division by zero fails with Division by zero. A float divided by zero
is infinite, and rendering it fails with Cannot render non-finite float.
The lexer also recognizes % and ~/, but the 0.149.1 parser rejects them
(Unexpected token: Mod, Unexpected token: TruncDiv).
baseTimeout = 5
timeout = baseTimeout * 2
configuredLabel = null
label = configuredLabel ?? "Untitled"
active = true
attempts = 2
eligible = active && attempts < 3{
"active": true,
"attempts": 2,
"baseTimeout": 5,
"eligible": true,
"label": "Untitled",
"timeout": 10
}Member access and null handling
length = name.length
safeName = account?.profile?.name
requiredName = safeName!!| Form | Behavior |
|---|---|
a.b | Reads a member. Fails with Property b not found when it does not exist. |
a?.b | Returns null when a is null, or when a is an object without b. |
a!! | Returns a, or fails with Null pointer exception (!!) applied to a null value. |
Type checks and casts
is and as are reserved words, but the 0.149.1 parser rejects them
(Unexpected token: Is). Use a typed property, such as text: String = value,
to check a value's type.
Conditionals and let
cacheSeconds = if (environment == "prod") 300 else 0
area = let (side = 4) side * sideThe condition must be a Boolean. Without else, a false condition produces
null, so the property is left out of output. Write an explicit alternative for
typed contract values. let (name = value) body binds a name for one
expression; let (name: Type = value) also checks the type.
Lambdas
double = (value: Int) -> value * 2
doubled = [1, 2, 3].map(double)
add = (a, b) -> a + b
sum = add(1, 2)Lambdas capture their lexical scope. Extra call arguments are ignored. Acore UI also has a compact lambda form for list keys; see Acore UI.
Errors and reads
required = configured ?? throw("configured is required")
region = read("env:REGION") ?? "local"| Form | Result |
|---|---|
throw(value) | Stops evaluation with User Error and the value. |
error("message") | Stops evaluation with the message. |
read("env:NAME") | The environment variable, or null when it is unset. |
read("prop:NAME") | An external property supplied by the host, or null. |
read("other"), read?("...") | Null in 0.149.1. read does not load files. |
read_env("NAME") | The environment variable, or an error when it is unset. |
Every read goes through the evaluator's security manager. Naming a path does not grant I/O. Contracts must not depend on environment values: declare a runtime secret instead.
Checked expressions in backend and UI code
Backend pure fn bodies, managed blocks, validator checks and Acore UI
expressions share a separate, checked grammar.
| Precedence | Operators |
|---|---|
| 1 | condition ? whenTrue : whenFalse |
| 2 | ?? |
| 3 | || |
| 4 | && |
| 5 | ==, != |
| 6 | <, >, <=, >= |
| 7 | +, - |
| 8 | *, /, % |
Other forms:
- Unary
!and-, member access.and?., and indexingitems[0], which returns an optional value. - Records
{title: value}, lists[a, b], record updates{task with title: t}and interpolated strings$"...". - Calls to declared pure functions and bounded methods:
Stringhaslength,trim(),toLowerCase(),toUpperCase(),contains(s),startsWith(s),endsWith(s)andslice(start, end);Listhaslength,contains(x),take(n),drop(n),sum()for integers andjoin(sep)for strings. - No lambdas,
**or|>. Arithmetic is checked, evaluation runs left to right,&&,||and??short-circuit, and string length counts Unicode scalar values.
project(id: "pure-example", version: "1.0.0")
pure fn label(count: Int32): String = count > 1 ? "many" : "one"
pure fn orNone(value: String?): String = value ?? "none"
pure fn isEven(value: Int32): Bool = value % 2 == 0