[ AxiomCore · Documentation ]
Objects, classes and functions
Build and amend objects, declare classes and type aliases, use this, outer and super, and write lambdas and pure functions in Acore.
This page covers how you shape data in Acore: objects, typed objects, classes,
type aliases, scope references and functions. The general-module examples were
evaluated with axiom eval from CLI 0.149.1; backend examples were checked with
axiom check.
Objects
A name followed by a block, or a brace literal, creates an object. Bracketed keys are evaluated.
metadata {
owner = "platform"
["x-contract-version"] = "1"
}
defaults {
retries = 3
region = "eu"
}
production = (defaults) {
region = "us"
label = "prod-" + super.region
}
service {
base = 10
nested { total = outer.base + 5 }
}{
"defaults": { "region": "eu", "retries": 3 },
"metadata": { "owner": "platform", "x-contract-version": "1" },
"production": { "label": "prod-eu", "region": "us", "retries": 3 },
"service": { "base": 10, "nested": { "total": 15 } }
}(defaults) { ... }anddefaults { ... }both amend an existing object: the result keeps every property you do not override.Name { ... }creates a typed object from a class, which supplies defaults. There is nonewkeyword and no constructor runs.- The parser does not expose
fororwhengenerators inside objects. Do not use those forms.
Scope: this, outer and super
| Reference | Points to |
|---|---|
this | The object being evaluated. A bare property name also resolves here. |
outer | The enclosing object |
super | The object being amended, or the parent class value |
Properties are lazy and immutable. A property cycle such as a = b and b = a
aborts evaluation: CLI 0.149.1 stops with a stack overflow instead of a
diagnostic. An import cycle reports Cycle: <module>.
Classes
hidden open class BaseService {
enabled: Boolean = true
timeoutSeconds: Int(this > 0) = 30
}
hidden class BillingService extends BaseService {
endpoint: String
}
billing = BillingService {
endpoint = "https://billing.example.com"
}{
"billing": {
"enabled": true,
"endpoint": "https://billing.example.com",
"timeoutSeconds": 30
}
}- A class describes a value shape. It may omit its body, take type parameters
(
class Box<T>) and extend one parent type. axiom evalrenders a class declaration like any other property, with its defaults. Mark classeshiddenorlocalto keep them out of output.- A class property with no default, such as
endpoint: String, must be set by each typed object. If the class itself is rendered, its null value fails the type check. - A typed object does not re-check overridden properties against the class's type or constraint in 0.149.1; see Types.
Type aliases
typealias Environment = "development" | "staging" | "production"
typealias StringMap = Mapping<String, String>Several contract positions are structurally typed, so the schema validation of each profile remains authoritative. A property typed with a literal-union alias is not checked against the literals in 0.149.1.
Functions
Lambdas are the callable form in general modules.
upper = (value: String) -> value.toUpperCase()
labels = ["one", "two"].map(upper)| Declaration | Behavior in 0.149.1 |
|---|---|
(params) -> expression | A closure. Call it with name(args) or pass it to a collection method. |
function name(params): Type { ... } | Parsed as a signature. It is not bound as a callable name (Undefined: name). |
external function name(params): Type | A member a trusted host must implement. Without a host binding the name is undefined. |
external does not let package code run. The standard library declares its
native members this way:
external function parse(source: String): Any
class Parser {
external function render(value: Any): String
}Annotations
@deprecated { replacement = "currentName" }
oldName: String = "legacy"An annotation is data for tooling. It has no effect unless the active compiler profile recognizes it.
Inheritance and composition
These forms are deliberately different.
| Syntax | Purpose |
|---|---|
class Child extends Parent | Class inheritance |
base { ... } or (base) { ... } | Amend an object value |
entity customer(model: Models.Customer) | Promote a model to a domain entity (backend) |
extend Models.Name { ... } | Older form that promotes an extracted model. extend accepts only Models.Name. |
amends "./base.acore" | Compose source before a build |
import "./shared.acore" | Load trusted source as a module |
A top-level extends "..." is rejected because it made source composition and
value inheritance ambiguous. See
Imports, amends and variants.
Backend pure functions and managed locals
project(id: "pure-example", version: "1.0.0")
pure fn normalizeTitle(value: String): String = value.trim()
pure fn label(count: Int32): String = count > 1 ? "many" : "one"- A
pure fndeclares explicit parameter and result types and a single bounded expression body. - It may call other pure functions and bounded string and list methods. The call
graph must be acyclic: recursion fails with
recursive or excessive-depth pure functions are forbidden. - It cannot capture state, host services, the clock or randomness.
- In a
managedblock,letcreates an immutable lexical local. Locals cannot be shadowed, and a local declared in a branch or handler cannot escape it.
See Managed logic and concurrency for statements and effects.
Related
Values, types and operators
Acore literals, built-in types, type expressions, operators, precedence and null handling, checked with Axiom CLI 0.149.1.
Imports, amends and variants
Choose the Acore keyword that matches the ownership and trust boundary, compose backend sources with amends, and select variants.