Browse documentation
Language

Concise research code

Write checked numerical code with parameter defaults, typed outcomes, compound updates, array selectors and explicit Result propagation.

The research syntax increments make checked numerical programs shorter while preserving Aner's types, ownership and error behavior. They add literal function defaults, expected type outcome construction, numeric compound updates, bracket array access, explicit Result propagation, native scalar aner.math and unit bearing scalar values through aner.units.

These features require the updated native development runtime built from this source. Earlier published executables may reject them. Match your runtime and editor to this documentation; see installation. Records, unit bearing array buffers, automatic dataset unit normalization and typed named repetition results remain planned work.

Implemented features

FeatureCurrent contractReference
Function defaultsTrailing scalar/null literals, including signed unit literals; exact declared types. Required parameters come first.Language
Outcome constructionAn expected Optional/Result type supplies omitted factory arguments, including nested factories.Optional, Result
Numeric updates+=, -=, *=, /= update an existing numeric var or numeric indexed array cell; unit bearing scalar bindings require an unchanged exact result type.Language
Bracket accessChecked scalar get/set for Array, DynamicArray and NDArray; exact Int64 coordinates.Array, NDArray
Result propagationresult? unwraps one success layer or returns the error through an explicitly annotated, compatible Result function.Result
Scalar mathematicsFloat64 square root, absolute value, power, exponential, natural logarithm and radians based trigonometry.aner.math
Scalar physical unitsExact Quantity<UnitCode>/Point<UnitCode> types, Float64 unit literals, compatible conversion and checked affine temperature arithmetic.aner.units

let/var, braces, named arguments, explicit numeric conversion and current mutable array semantics remain in use. Range iteration is already supported. The additions do not introduce closures, records, pattern matching, slices, general collection iteration or implicit Int64/Float64 promotion.

Run a complete local program

Use the complete research syntax source. With the source bundle's examples directory in your current folder:

sh
aner check examples/research_syntax.aner
aner run examples/research_syntax.aner
aner check examples/math_basic.aner
aner run examples/math_basic.aner
aner check examples/units_basic.aner
aner run examples/units_basic.aner
aner check examples/units_lab_monitoring.aner
aner run examples/units_lab_monitoring.aner

The math example separately exercises every scalar function. The unit basics and laboratory observation example add checked distances, times and temperatures. All four examples contain their complete input fixtures, use no external data or credentials, and create no file.

aner
// Requires the updated native development runtime with research syntax support.
// Complete local example: defaults, outcome inference/propagation and checked indexing.
import aner.math

fn scale(value: Float64, factor: Float64 = 2.0) -> Float64 {
    return value * factor
}
fn positive_root(value: Float64) -> Result<Float64, String> {
    if value < 0.0 { return Result.err("value must be nonnegative") }
    return Result.ok(math.sqrt(value))
}
fn labeled_root(value: Float64) -> Result<String, String> {
    let root = positive_root(value)?
    return Result.ok("root=" + String(root))
}

let missing: Optional<Float64> = Optional.none()
let nested: Result<Optional<Int64>, String> = Result.ok(Optional.none())
let readings = Array<Float64>(size: 3, fill: 0.0)
readings[0] = 3.0
readings[1] = 4.0
var squares = 0.0
for index in Range(readings.len()) {
    squares += math.pow(readings[index], 2.0)
}
let matrix = NDArray<Float64>(shape: List(2, 2), fill: 0.0)
matrix[1, 1] = math.sqrt(squares)
matrix[1, 1] += 1.0
var count = 3
count *= 4
count /= 2
count -= 1

print(scale(3.0))
print(scale(factor: 4.0, value: 3.0))
print(missing.is_none())
print(nested.unwrap().is_none())
print(matrix[1, 1])
print(count)
print(labeled_root(25.0).unwrap())
print(labeled_root(-1.0).unwrap_err())

Expected output:

text
6.0
12.0
true
true
6.0
5
root=5
value must be nonnegative

The named factor call evaluates each supplied expression once in source order. The arrays retain their native typed buffers. The negative root uses an explicit error Result; labeled_root returns that same error payload through a new Result<String, String> wrapper without evaluating its later success return.

Defaults and expected types

Defaults belong to user function and class method parameters. They must be literal Int64, Float64, Bool or String values, compatible null, or a negated numeric literal. Names, computations, calls and collection/outcome constructors are not default expressions. Class field defaults and custom constructors are not added.

At a call, explicit arguments evaluate first in source order; omitted defaults are supplied afterward in formal order. Positional arguments still precede named arguments. Unknown/duplicate labels and missing required arguments fail checking. factor: 2 is not a Float64 default; use 2.0 when the parameter is Float64.

Expected Optional/Result types come from annotated bindings, assignments, explicitly declared returns, typed user call arguments, declared class constructor fields and wrapper unwrap_or fallbacks. Nested factories receive their known payload type. Outside such a context, Optional.none() cannot infer T, and Result.ok/Result.err cannot invent the inactive alternative. Explicit type arguments remain valid. An unannotated Optional.some(3.5) can infer Float64 from its payload.

Contextual construction supplies an already known type; it is not automatic conversion, a general generic function system or a change to nullable class references. Node? remains separate from Optional<Node>.

Mutation and evaluation order

Bracket reads return the exact array element type. Ordinary bracket writes support all existing Int64, Float64, Bool and String array element types. Numeric compounds require matching Int64 or Float64 operands; String/Bool compounds, %= and object field compounds are unsupported. A name compound requires an existing var; it cannot silently declare a variable. A let array binding still allows element mutation under its established buffer contract.

The opening [ must be on the same physical line as the receiver's final token. Coordinate expressions inside the selector may span lines. This keeps a new bracketed statement from silently becoming an index on the previous statement. Array/DynamicArray take one coordinate; NDArray takes one per runtime axis, from one through eight. String, Dictionary, List and Tensor retain their explicit accessor APIs.

For an indexed assignment, evaluate the receiver and coordinates once, validate the address, then evaluate the right side and write. A compound update also captures the prior cell before right side effects. The resulting update uses that captured prior value even if the right side mutates the same cell. Right side effects are not rolled back if arithmetic or the final write fails.

Int64 arithmetic keeps its overflow and division by zero checks. Scalar Float64 arithmetic can produce nonfinite values; typed Float64 array storage rejects them. Brackets preserve current sharing: Array/NDArray reshape aliases see each other's writes, and copies remain independent. Brackets access one scalar; they do not create views or slices.

Result control flow and diagnostics

Postfix ? requires a Result operand and an explicitly declared enclosing -> Result<T, E> function. Error type E must match exactly. The successful payload type may differ from the enclosing success type, as Float64 becomes String in labeled_root above.

Evaluate the operand once. Success unwraps one layer. Error skips remaining operands, arguments and statements in that function and returns one new enclosing error wrapper carrying the original error payload. Completed earlier effects remain completed. The enclosing function still needs an explicit success return; propagation does not wrap successful values automatically.

Put ? on the same line as the operand's final token; for a multiline call, this can be beside its closing ). Top level use, Optional propagation and inferred Result return boundaries are unsupported. Use a binding or (nested?)? for nested Results; adjacent ?? is rejected. Propagation never catches native diagnostics or converts failures to missingness.

Wrong static types, inference contexts or propagation boundaries produce checker diagnostics. Invalid array coordinates and array numeric results retain R3001; inactive Optional/Result access retains R3404; math domain/nonfinite/range failures use R3601. A native math failure inside a checked repetition task follows the repetition's normal task diagnostic and fails the batch without publishing incomplete results. Native runtime failures retain the existing persistent session reset behavior.

Scientific boundaries

aner.math returns raw Float64 values. Its trigonometry uses radians, and log is natural logarithm. Each function has explicit finite/domain/range rules; exp and pow reject nonzero results rounded to zero while accepting representable subnormals. See the complete math contracts.

aner.units now provides scalar Quantity<m> and Point<degC> types using the same bounded registry as SemanticTensor and EvidenceTensor. Write 2.0@m, 20.0@degC and 5.0@delta_degC; use quoted fixed codes such as 3.0@"m/s". Quantity/Point magnitudes remain Float64, with no implicit Int64 promotion or conversion between exact declared unit types. Point minus Point yields a temperature interval; Point plus an interval yields a Point. Point plus Point, Point scaling and Point negation are rejected.

The complete scalar basics and laboratory observation example cover mixed unit normalization, typed fields, Result propagation and temperature thresholds with local data. See the unit reference for allowed products, literal defaults, compound updates, exact comparisons, finite range checks and explicit .value() export. Scalar units do not add source aware uncertainty or silently label packed Array/Tensor buffers. Unit aware table ingestion, unit bearing array buffers and general nonlinear uncertainty propagation remain planned work.

parallel.repeat continues to use a directly named checked task, a List parameter graph and scalar/numeric List outputs retained as SimulationResults. Immutable scalar quantities and points are admitted inside the private parameter snapshot and checked local task calculations; outputs still require explicit .value() export to the existing numeric result schema. Typed configuration/result records and named result columns remain planned; the syntax additions preserve worker resource admission and seeds. See repetition and the heat diffusion study for the existing execution and numerical contracts.

Continue with the formal language reference, aner.math, aner.units, Result, Optional, Array and NDArray for complete API details.

The runnable research example page shows the complete current source and its runtime requirements. Download the source for local execution.

Aner documentation · Reference and guides