Local declarations and expression bodies — implemented
Noncapturing FUNCTION/SUB declarations may appear in an enclosing lexical block. They require declaration before use, can recurse and do not become module exports. Captures and generic-parent local specialization remain restricted. A local helper cannot read an outer local as an implicit capture.
PRINT Square(3.0)
FUNCTION Square(X AS DOUBLE) AS DOUBLE = X * XExpression bodies use ordinary checking/ownership/error rules and need no END FUNCTION. SUB has no successful result and allows bare RETURN/fallthrough; returning a value is an error. FUNCTION must return a matching successful value on every reachable successful exit; bare RETURN/fallthrough fails. Both support FAILS and ordinary suspending calls. RETURN ERROR selects failure, not successful return.
Checked function values — implemented
FUNCTION Apply(handler AS CALLABLE(INTEGER) AS INTEGER, value AS INTEGER) AS INTEGER
RETURN handler(value)
END FUNCTION
FUNCTION SquareInt(value AS INTEGER) AS INTEGER = value * value
PRINT Apply(SquareInt, 7)A CALLABLE signature lists parameter types/modes, optional AS success type
(no AS means SUB), and optional FAILS (ErrorType, ...). Named noncapturing functions
produce callable values; indirect calls enforce access/result/error contracts.
Owning copies have independent cleanup. Signatures cannot be compared or hashed.
Read-only assignment may widen a failure set; BYREF signatures must match exactly.
Callables use required positional arguments; declaration parameter defaults/names
are not an unchecked indirect-call facility. See checked-call ABI
and layout
.
Generic declarations can use type parameters inside signatures. Earlier argument types supply context for overloaded function references; signatures must become concrete before invocation. Nested signatures, declared errors, BYREF/BYVAL modes and borrowed-result origins retain their ordinary checks. For example:
FUNCTION Apply[T](value AS T, transform AS CALLABLE(T) AS T) AS T
RETURN transform(value)
END FUNCTIONThis does not infer an arbitrary error set: a fallible generic callback needs an
explicit checked FAILS contract. Generic CALLABLE(TAKE T) remains rejected when
T is unresolved; concrete resource-consuming signatures work. Inferring T from
an overloaded callback before other arguments provide context remains ambiguous.
Noncapturing foreign handlers
CALLBACK(...) selects a generated C ABI entry; CALLABLE NOSUSPEND(...) keeps
the BASIL ABI for reviewed binding adapters. C CALLBACK must be infallible;
BASIL NOSUSPEND may retain declared errors. Both check nonsuspending targets and
transitive calls. Neither captures locals. C callback
creation binds its coordinator thread before C can invoke it. Unsafe functions
cannot become safe delegates. Full contracts and GTK example
.
PUBLIC and PRIVATE — implemented scope
Module FUNCTION/SUB, TYPE, ERROR, ENUM and CONST declarations support PUBLIC/PRIVATE. Unmodified declarations remain public for compatibility. PRIVATE is enforced for qualified imports; public signatures cannot leak private nominal types/error sets. Local declarations cannot be exported with PUBLIC. PUBLIC is not C EXPORT or permission for unsynchronized mutation. Imported modules execute no initialization. Mutable module variables remain unimplemented; opaque types can expose explicitly PUBLIC readonly fields under the record rules . PUBLIC DIM does not reinterpret entry locals as globals. Imports defines current name resolution.
Lambdas and captures — implemented subset
minimum=10
matches=Filter([1,10,20],(n) => n>=minimum)
square=(x AS DOUBLE) => x*x
PRINT LEN(matches)
PRINT square(3.0)The expression form is (parameters) => expression; () has no parameters.
Use FUNCTION(parameters) [AS result] [FAILS …] through END FUNCTION for a block,
or SUB(parameters) through END SUB for a procedure. Parameter types need AS or a
concrete expected CALLABLE. Results and escaping errors infer from ordinary body
checking unless declared; inconsistent/missing successful returns are rejected.
An inferred lambda can specialize inside a generic parent.
Copyable free locals become independent readonly snapshots at construction. Captured strings/collections/callables own their copies and clean up on ordinary, failure and cancellation exits. Copies of closures are independent values. A later mutation of the original does not change a capture. Explicit local DIM and nested lambda parameters bind local names, rather than capturing matching outer resource variables. Named local helpers still do not capture implicitly.
Resources and task/channel capabilities cannot be captured. Pass an owned context explicitly to a library API, using TAKE for named resources, or pass ordinary checked function arguments. Mutable shared capture cells, borrowed/owning resource captures, anonymous CALLBACK/NOSUSPEND adaptation and nested named declarations inside anonymous bodies are not implemented. No GC/reference counting is added.