Language Features
Complete reference for Loxel v2 — a modern, expression-oriented language with optional static typing, multilingual keywords, and built-in concurrency.
The statuses listed on the page are for developers only, and do not reflect the delivered binary. Everything is currently in beta, and subject to change.
Variables & Constants ✅ Working
Use let for mutable variables and const for immutable constants. Type annotations are optional; Loxel infers types automatically.
Example
Expressions & Blocks ✅ Working
Everything in Loxel is an expression that returns a value — if, match, try, and blocks all yield results.
Example
Only a bare trailing expression becomes the block's value — a trailing def is a declaration, not an expression, so it is not picked up:
Strings & HEREDOC ✅ Working
Backtick strings and HEREDOC both interpolate with ${}. HEREDOC (<<<END) just lets that span multiple lines. The nowdoc form (<<<'END') treats ${} as literal text instead of interpolating it.
String interpolation
HEREDOC multi-line strings
Control Flow ✅ Working
Standard if/else, unless, while, do-while, C-style for, range-based for-in, and comprehensions.
Example
Type Annotations ✅ Working
Types are optional but recommended for public APIs. Loxel supports three type-checking modes: OFF, WARN, and STRICT.
Primitive types & inference
Generics ✅ Working
Generic classes and functions use <T> type parameters. Type bounds use extends. Works in the tree-walker, bytecode VM, and native/LLVM backend. Box<Number> is a first-class parameterized-class value in all three modes — it can be aliased, passed around, and called later (including with named constructor arguments). Method-level type arguments (obj.method<Number>(x)) are validated in all three modes: type-argument arity, declared bounds, and parameter types. Type arguments are erased for execution (as in most dynamically-typed languages) but recorded on instances for runtime checking of generic method parameters; the native backend additionally validates instantiation arity, non-generic misuse, and type bounds at compile time when the class is statically known, and at runtime otherwise.
Example
Union & Optional Types ✅ Working
Union types express "this OR that" with |. T? is shorthand for T | Nil.
Example
Classes ✅ Working
Classes use def init for constructors and self (not this) for the instance reference. The @field syntax is not supported in v2.
Example
Inheritance ✅ Working
Single inheritance with extends. Use super.init() to call the parent constructor and super.method() to call overridden methods.
Example
Interfaces & Traits ✅ Working
Interfaces define contracts. Traits (mixins) provide reusable implementation. A class implements interfaces and uses traits.
Interface
Traits (mixins)
Property Promotion ✅ Working
Annotate constructor parameters with visibility/mutability modifiers to auto-create fields. Supported in the tree-walker, bytecode VM, and native/LLVM backend.
Example
Visibility Modifiers ✅ Working
public (default), private, and protected control access to fields and methods. Enforced in all three modes, including the native/LLVM backend. Native (and the tree-walker) raise catchable errors; the bytecode VM raises the same messages but treats them as fatal. Note on inheritance: native resolves the calling class lexically, so a base-class method (e.g. via super.init) can always touch the base's own private/protected fields, and subclasses can access inherited protected (but not private) fields — the tree-walker and VM currently derive the calling class dynamically and each rejects one of those base-method patterns.
Example
Operator Overloading ✅ Working
Define a method whose name is the operator symbol — def +(other) — to customize behavior for +, -, *, **, /, %, ==, !=, <, >, <=, >=, <=>, and the unary -@ / !. There is no operator keyword.
Example
Compound-assignment contract: in-place += vs. allocating +
A class may also define +=, -=, *=, /=, or %= directly, distinct from its +-style method — mirroring Python's __iadd__ vs. __add__. x += y tries the class's own += method first (mutate self in place, no allocation) and falls back to + when += isn't defined.
Decorators ⚠️ Partial
Decorators wrap functions or classes. Fully working in tree-walker. Bytecode support in progress.
Example
Match Expressions ✅ Working
Nine pattern types: literal, variable, wildcard, array, object/map, type, range, guard, and OR. Works in all modes.
Core patterns
Match as expression with complex example
Operators ✅ Working
Arithmetic (incl. exponentiation **), comparison (incl. strict === / !==), membership (~> / <~, Unicode ∈ ∋ ∉ ∌), logical, assignment, null-handling, pipeline, spread, and type-checking operators.
All operators quick reference
Operator precedence (highest → lowest)
Functions & Parameters ✅ Working
Named functions with def, arrow shorthand, default parameters, named arguments (colon syntax only), rest parameters (PHP-style unified map), lambdas, and higher-order functions.
Function syntax overview
Lambdas, closures & higher-order functions
Async / Await ✅ Working
Async functions return Promise<T>. await suspends execution until the Promise resolves. Use Promise.all for concurrent requests.
Example
Channels & Spawn 🚧 In Progress
Channel-based concurrency and thread spawning. Support in progress.
Example
Enums 🚧 In Progress
Enums define a fixed set of named variants. Variants can carry associated data (like Rust enums) and work with pattern matching.
Example
Structs ✅ Working
Structs are value types — copied on assignment. Use them for small, immutable data (Point, Color, Vec2). Use classes for objects with identity and inheritance.
Value semantics vs. class reference semantics
Destructuring ✅ Working
Extract values from arrays, maps, and structs using destructuring assignment and function parameter patterns.
Array & object destructuring
Arrays ✅ Working
Dynamic arrays with rich built-in methods. Slice with arr[1..3] (exclusive) or arr[1..=3] (inclusive).
Array operations
Maps ✅ Working
Key-value dictionaries with property shorthand, spread, and comprehensive methods including entries(), clear(), and empty().
Map operations
Sets & Tuples 🚧 In Progress
Sets store unique values with union/intersection/difference operations. Tuples are fixed-structure named pairs.
Sets
Tuples
Module System ✅ Working
Per-module scope isolation, export-only visibility, and singleton execution. Supports stdlib (std::), relative paths (./), and bare package names.
Defining & importing a module
Import forms & module singletons
Multilingual Keywords ✅ Working
Write code in 7 languages. Keywords and type names are internationalized. Run with loxel run --lang es.
Examples in multiple languages
| Language | Function | Class | String | Number |
|---|---|---|---|---|
| English | def | class | String | Number |
| Español | def | clase | Cadena | Numero |
| Français | def | classe | Chaîne | Nombre |
| Deutsch | def | klasse | Zeichenkette | Zahl |
| Português | def | classe | Cadeia | Numero |
| 日本語 | def | クラス | 文字列 | 数値 |
| 中文 | def | 类 | 字符串 | 数字 |
Error Handling ✅ Working
Standard try/catch/finally blocks, custom error types via class inheritance, and try as an expression.
Example
Built-in Functions ✅ Working
Core built-ins always available without an import.
Output, type conversion & utilities
String & Math ✅ Working
String methods
Math module
File, HTTP & JSON 🚧 In Progress
File I/O
HTTP Client & JSON
Data Structures ✅ Working (V2)
Import from std::collections, std::trees, and std::graphs.
Stack, Heap, Deque
Binary Search Tree, AVL Tree, Trie
NumPy & Machine Learning ✅ Working (V2)
N-dimensional arrays (std::numpy), ML algorithms (std::ml), and statistical computing (std::statistics).
NumPy-style arrays
ML classifiers & regression
AI Training & LLMs ✅ Working (V2 · compiled)
A full pure-Loxel deep-learning stack — no PyTorch. Threaded f32 tensors and
a fused 4-bit kernel (std::tensor), and real-model QLoRA fine-tuning
plus Q4 KV-cache inference (std::llm), validated end-to-end on
SmolLM2-360M. This stack targets the LLVM-compiled backend
(the reference for these modules) — compile with -O2 --cpu=native; it is not run
through the interpreter.
QLoRA fine-tuning (4-bit frozen base + trainable adapters)
Q4 KV-cache generation (temperature + top-k)
std::tensor — threaded matmul & fused 4-bit kernel
Execution Modes ✅ Working
Three modes: tree-walking interpreter (default, full feature support), bytecode VM (faster, most features), and LLVM compiler (native code, 50–100× speedup).
| Mode | Speed | Features | Usage |
|---|---|---|---|
| Tree-walker | Baseline | All features | loxel script.lox |
| Bytecode VM | 18× faster | Core features | loxel script.lox --bytecode |
| LLVM | 50–100× faster | Native binary | loxel compile script.lox -o out |
| REPL | N/A | Interactive | loxel or loxel repl |
REPL special commands
Language-Level Events ✅ Working
Event decorators on class methods intercept lifecycle events for AOP, logging, validation, and metaprogramming.
Event hook decorators
Built-in method decorators
| Decorator | Trigger | Parameters |
|---|---|---|
@onCall | Before any method call | method_name, args |
@onReturn | After method returns | method_name, result |
@onThrow | Exception thrown | method_name, error |
@onPropertyGet | Property read | property_name |
@onPropertySet | Property written | property_name, new_value |
@onInstantiate | After init() | none |
@onInherit | Class subclassed | child_class |
Unified Object Model ✅ Working
All primitive values behave as objects with methods. Internally they remain efficient (NaN-boxed doubles, bit-pattern booleans) — method calls dispatch directly to C++.
Primitive class contracts: every inline primitive is an instance of its core Loxel class (String, Number, Boolean, Array, Map, Set), and every core class extends Object. The class definitions in stdlib/core/*.lox are the declared contract — including operator methods with typed parameters like def <(other: String). Class methods may delegate to native functions, and the engines fast-path primitive receivers equivalently, but the semantics are the ones written on the class; subclass overrides dispatch through the method table and win. (Single-source build-time embedding of the core classes and typed operator contracts: ✅ landed 2026-07-03.)
Primitive methods
Abstract Classes 📋 Planned
Abstract classes define partial implementations. Subclasses must implement all abstract methods. Instantiating an abstract class is a runtime error.
Planned syntax
Static Properties & Methods ⚠️ Partial
The static keyword works in the bytecode VM and the native/LLVM compiled backend. static let/static const fields may have an initializer, evaluated once when the class is defined. Both the bytecode VM and the native/LLVM backend enforce visibility and const/readonly mutability on static fields with matching error messages (write-once: the initializer or first assignment succeeds, later writes throw; native errors are catchable, VM errors are fatal). Static members are accessed via the class name, not self.
Static keyword (working)
Static variable: visibility & mutability
Quick Reference
Feature support matrix across execution modes.
| Feature | Tree-walker | Bytecode VM | LLVM |
|---|---|---|---|
| Variables / const | ✅ | ✅ | 🚧 |
| Functions & closures | ✅ | ✅ | 🚧 |
| Classes & inheritance | ✅ | ✅ | 🚧 |
| Interfaces & traits | ✅ | ✅ | 🚧 |
| Generics | ✅ | ✅ | ✅ |
| All 9 pattern types | ✅ | ✅ | 🚧 |
| Default parameters | ✅ | ✅ | ✅ |
| Named arguments | ✅ | ✅ | ✅ |
| Rest parameters | ✅ | ✅ | ✅ |
| Async / await | ✅ | ✅ | 🚧 |
| i18n support | ✅ | ✅ | 🚧 |
| Module system | ✅ | ✅ | 🚧 |
| Language events | ✅ | ✅ | 🚧 |
| Unified object model | ✅ | ✅ | 🚧 |
| Channels / spawn | ❌ | ❌ | 🚧 |
| Abstract classes | 📋 | 📋 | 📋 |
| Static properties | 📋 | ✅ | 🚧 |
Best Practices
Type annotations
Error handling
Pattern matching vs. if/else
Known Limitations
- LLVM: Compiler in progress (Phase 7). Use
--bytecodefor production. - Channels / spawn: Not yet implemented. Async uses Promises; channel-based concurrency in progress.
- Visibility/mutability across modes: Enforced in all three modes (native records per-class field metadata and checks it at every field access). Divergences that remain: VM errors are fatal while native/tree-walker errors are catchable; the tree-walker has no static fields; and for inherited fields the lower modes derive the calling class dynamically (each rejecting a legitimate base-method access pattern that native's lexical resolution allows).
- Abstract classes: Designed but not yet implemented (Phase 19).
- Generics in LLVM: Generic instantiation works, and
Box<Number>is a first-class parameterized-class value (aliasinglet B = Box<Number>; B(x)and named/spread constructor arguments keep the type arguments). Arity/non-generic/bound errors are reported at compile time when the class is statically known; arity and non-generic misuse are also validated at runtime for dynamic class values. Type arguments are erased for execution, but each generic instance records its concrete type arguments, so a method parameter typed as a class type parameter (def set(v: T)) is validated at runtime in all three modes —Box<Number>().set("x")raises the sameType mismatch for parametererror natively, in the VM, and in the tree-walker. Method-level type arguments (obj.method<Number>()— arity, bounds, and parameter validation) and concrete/composite parameter types on generic receivers (v: Number,vs: Array<T>— container kind checked, element types unchecked) are likewise enforced in all three modes. Remaining nuances: native validates method-level type-argument bounds by type NAME (registered class hierarchies and primitives are exact; unresolvable names are accepted conservatively), and element types ofArray<T>/Map<K,V>arguments are not deep-checked in any mode. - Object pattern guards in bytecode: Guards on object/map patterns work in tree-walker; bytecode support in progress.
- Promise.all / race: Not yet implemented in any mode.
Workarounds
- Use
loxel script.lox --tree-walkerfor full feature access.
Comments ✅ Working
Three comment styles:
//single-line,/* */multi-line (nestable), and/** */documentation comments.Example