Skip to content

Latest commit

 

History

History
19 lines (16 loc) · 4.31 KB

File metadata and controls

19 lines (16 loc) · 4.31 KB
title Known limitations
sidebar
order
2

Known limitations

The deferred parts:

  • Polymorphism is overloading. Overloading (ad-hoc, exact-type dispatch) is the polymorphism; type variables are deferred, and the matchers are compiler-provided. The module system is the built-in core.* modules and file-path imports, reached through qualified access; selective import, re-export, and aliasing are deferred.
  • Closures are monomorphic. Lexical capture works end-to-end (= by value / := by reference; see Closures), including recursion of non-capturing nested functions, capture across nesting levels, and capturing-then-calling another closure. A closure can be passed to a function-typed parameter and called there, and returned from a function — its captures live on the GC heap, so they outlive the frame that made them. Deferred (each needs the closure's type threaded through inference): capturing a polymorphic value and generic closures.
  • Closure values are lambdas and closure bindings. A closure is passed (or returned) as a lambda literal or a named closure binding; a top-level function or an overloaded name travels as a lambda that calls it, and the compiler says so ("a function name is not a value yet — wrap it in a lambda that calls it"). Function names as values are deferred.
  • A pattern tests one level. A constructor pattern's payload sub-pattern is irrefutable — a binding (Ok(x)) or _ (Ok(_)); dispatch reads the variant tag, and the arm body compares the bound payload. A match on a Text or a Bool is covered by a catch-all arm; literal patterns for them are deferred.
  • A field write's path ends at a binding. A write whose root is a call result (same(m).v := 5 on a :=-bound m) passes the checker — the value is mutable — and its lowering is deferred; bind the result first (h := same(m), then h.v := 5). A Result signature's payload is Generic, so a record passed through a generic Result parameter is outside the deep-immutability analysis; a user sum with a concrete record payload is inside it.
  • A named-composite sum payload is a record, and a record field is a built-in type or an array. A variant may carry a named record (Post(Body)); a named sum payload is deferred, and a record field of a user type ({ inner :: Inner }) is deferred.
  • A range consumed directly by an array method iterates its endpoints; every other consumption builds the array. A lo <- hi fed straight to .each/.map/.filter/.reduce iterates its endpoints — (1 <- 100000000).each(...) is a counter — so "do this N times" scales (see ranges). Indexing, .size, binding to a name, and passing to a function build the whole array at 8 bytes per element, and the first method of a chain is the lazy one — the later links consume the arrays it produces.
  • A stack overflow is reported as QN507. ^ runs on the scheduler's seed fiber, whose stack is 8 MiB — a process stack's size, with the same recursion depth. Recursion of unbounded depth is written as a self-tail-call, which is lowered to a loop and runs in constant stack.
  • Concurrency is partly built. The model is locked; the fiber scheduler, reactor, time.@sleep, the deferred-value primitives (io.@readStdin, net.@tcpRequest), the block-scope join for a launch made directly in a < > block (allSettled, every fault reported by its own launch site), the atomic-binding syntax @name := … — its reassignment rejected when the right side forces a deferred value — the raw TCP server layer (net.@tcpServe/Connection/Server), and the fiber-sharing check the checker enforces against net.@tcpServe's handler — a non-atomic := binding it reaches, directly or through a call, is a compile error — run. Remaining for 1.0: an overlap showcase, deferred composites, cross-function pipelining (a launch made inside a called function, joined by the block that made the call), file primitives, and the M:N runtime with atomic types.