Evaluation and initialization
This section specifies the sequencing guarantees exposed by E# programs. It is deliberately narrower than a machine-level CPU memory model: atomicity and inter-thread synchronization are provided by the CLR/BCL APIs that a program chooses to use.
Evaluation order
Section titled “Evaluation order”Call = Callee "(" [ Argument { "," Argument } ] ")" .Conditional = Expression "?" Expression ":" Expression .ShortCircuit = Expression ( "&&" | "and" | "||" | "or" | "??" | "?." ) Expression .Operands and call arguments evaluate left to right. Every argument has completed evaluation before the callee body begins. Named arguments retain this evaluation order: they are associated with parameters by name, but are evaluated in the written left-to-right order before invocation. The language shall not reorder visible side effects across these boundaries.
&&/and, ||/or, ??, and ?. evaluate their right side only when their left side requires it. A
conditional evaluates its condition and exactly one branch. Result propagation (?) may return from the
enclosing function at its occurrence; deferred cleanup still runs on that exit path.
Initialization order
Section titled “Initialization order”Value construction applies field defaults as the value is formed. For a class construction, the sequence is:
selected base constructorfield defaults of the constructed classselected init bodyFor a class primary-constructor header, capture stores precede field defaults and the parameterless init { }
epilogue follows them. Constructor delegation with : this(...) transfers responsibility for the base call and
field defaults to the delegated constructor, then executes the delegating body.
Namespace state and static-facet fields initialize through CLR type initialization. When a namespace declares
init { ... }, its host has an explicit .cctor, is not beforefieldinit, initializes state in declaration
order, then executes the init body. It runs once at first host use; an exception follows normal CLR failed
type-initialization semantics. See Namespace hosts for the source rules.
Deferred cleanup
Section titled “Deferred cleanup”defer { body } registers body for execution when its lexical scope exits. Multiple registrations execute
in LIFO order. Cleanup executes on fallthrough, return, loop transfer, error propagation, and exception
unwinding. It lowers to the CLR’s try/finally mechanism, so cleanup is sequenced before control reaches
the destination outside the scope.
func read() -> Result<string, string> { let handle = openFile() defer { handle.Close() } return parse(handle)? // Close still runs on the early return}Concurrency visibility
Section titled “Concurrency visibility”Copy/reference semantics do not by themselves make compound operations on shared state atomic. A class field,
namespace var, or heap pointer can be shared; read-modify-write operations on it must use the appropriate
BCL synchronization primitive when concurrently accessed. E# exposes the BCL directly, including
Interlocked, Volatile, locks, concurrent collections, CancellationToken, Task, and channels.
Structured concurrency and chan<T> give ownership, completion, cancellation, and message-passing rules;
they do not reinterpret arbitrary shared mutable fields as synchronized. Prefer passing values through channels
or isolating mutation behind an explicit synchronization boundary. The language supplies no unsafe escape
hatch that would weaken CLR GC tracking or allow unmanaged pointer arithmetic.