Explanation
Tradeoffs and Current Boundaries
Understand the design decisions, alternatives, and limits.
OJaml chooses a compact compiler over a complete OCaml clone. The current surface demonstrates inference, top-level and nested modules with local type declarations, abstract type signatures, concrete record and variant type manifests, val signatures, top-level and local function recursion, high-arity closures, staged closures, sequencing, forward pipelines, tuples, tuple projection, record and algebraic data type declarations with type parameters, value annotations, function parameter annotations, higher-order function type annotations, top-level opens for built-in and user-defined namespaces, structural records, field access, tuple/record/list/array/set/map/constructor destructuring, collections, pattern matching, WebAssembly emission, and editor tooling, but it does not yet include file imports, functors, exceptions, or a garbage collector.
The runtime makes a similar bargain. Bump allocation and linked heap layouts keep allocation code short and predictable, but allocated data lives for the lifetime of the module instance. Collection helpers now trap common invalid accesses instead of reading arbitrary memory, but those traps are not recoverable OJaml exceptions. A production ML runtime would need garbage collection, richer failure values, and a way to recover from or report runtime faults inside the language.
- Static typing protects source-level meaning, while the backend keeps a uniform i32 representation.
- Direct calls stay simple, while closure values use generated arity-specific function-table indirection only when needed.
- Polymorphic builtins are typed precisely, but their runtime helpers operate on uniform pointers and integers.
- The editor tooling benefits from source spans carried through the parser and checker.