Moth says no to many features that other languages include. Here is why.
No general macros
Macros create a second language inside your code. Moth uses templates, constants and builder directives for compile-time work instead.
No general closures or higher-order function values
General closures and higher-order function values add complexity to the type system and make code harder to follow. Moth uses reactivity for the common UI pattern that closures usually solve.
No dynamic trait values
Dynamic trait values need runtime dispatch and hidden wrappers. Moth uses choices for runtime variety and generic bounds for static reuse.
No operator overloading
Operators in Moth always do the same thing. You can't redefine + or == for your own types.
No reflection
You can't inspect types at runtime or write code that examines other code's structure. This keeps programs predictable and easy to read.
No platform-specific source branches
Moth code does not ask whether it is compiling for an operating system, architecture, JavaScript or Wasm. Builders handle that choice.
No explicit lifetime and ownership type system
Moth keeps lifetime and ownership rules behind the compiler. Source code uses explicit copies and exclusive access without adding lifetime or ownership annotations.
No general blocks or control-flow labels
Structured control flow introduces scope. Moth has no dedicated general lexical-block construct, statement labels, labelled loop exits or goto. block is an ordinary identifier, so block: declares a region like any other valid name: header. Exact _: is invalid.
The pattern
Each excluded feature has a Moth replacement that is more constrained and more explicit. The language trades generality for clarity.
This file forms the exhaustive inventory of language mechanisms outside Moth's design scope. A listed feature needs an explicit change to the language philosophy before implementation.
Macros and broad metaprogramming
General-purpose macros, procedural macros, derive macros and AST macros create a second compile-time language and make code harder to inspect. Templates, constants and builder directives provide the constrained compile-time surface.
General closures and broad function-value mechanisms
General closures, anonymous callable values, generic function values and higher-order polymorphism are outside scope. These mechanisms add broad function-value semantics and solver pressure. Reactivity covers many closure-heavy template cases without adding general function values. Hidden event-handler closures remain outside the language model as well.
Dynamic trait values
Dynamic trait values and trait objects require erased wrappers, runtime dispatch, dynamic-safety rules, backend-specific runtime support and a second meaning for trait names. Use choices for runtime heterogeneity and generic trait bounds for static reuse.
Trait-level programming
Trait inheritance, trait aliases, trait composition, default methods, associated types and associated constants turn traits into a type-level programming system rather than simple method contracts.
Generic traits and generic trait methods
Generic traits and generic trait methods make trait solving significantly more complex and create Rust-like abstraction patterns.
Conformance extensions
Blanket, conditional, negative, specialised and structural conformance require coherence and specialisation rules outside Moth's simplicity target. Structural conformance must not silently imply conformance from matching method shapes. Type must TRAIT stays explicit. File-local evidence-backed bound dispatch outside reusable conformance, output coercion, operator integration, automatic primitive conformance and derive-style hashing, ordering, formatting, iteration or serialisation families also stay outside scope.
Constraint sublanguage
Type-set constraints, union constraints, underlying-type constraints and user-defined numeric or operator constraints turn generic bounds into a constraint sublanguage. Generic bounds name traits only. where clauses remain outside the source constraint model.
Operator overloading
Operators stay compiler-owned and predictable. Moth has no source-visible operator overloading.
Source-authored receiver extensions
Cross-file, builtin, imported and foreign receiver extensions remain outside scope. Source-authored receiver methods belong only to the same file as their nominal receiver type. Methods for dependency package types and external opaque types must use free functions.
User-extensible map semantics
User-defined HASHABLE, custom map hashers or comparers and user-defined keys for builtin maps stay outside the language. Builtin map syntax stays scalar-keyed. More sophisticated maps belong in packages as ordinary structs.
Builtin keys remain limited to String, Int, Bool and Char. The builtin map surface excludes Float, structs, choices, collections, maps, traits, functions, external opaque types and generic parameters as key families. It also excludes hashset syntax, map equality, indexing syntax, mutable entry APIs, const maps, fixed-capacity maps and specialised map variants.
First-class result values
First-class public Result values and result pattern matching stay outside the language. Error!, postfix ! and catch form the error path. Authors can define ordinary choices when they want explicit result-like domain values.
User-defined cast extensions
User-defined cast target types, generic cast target parameters, external opaque cast targets, generic cast traits, broad return-type-directed conversion and implicit conversion chosen from distant context remain outside scope. Cast evidence stays compiler-owned and explicit.
Exceptions and catchable panic systems
Expected failures use Error!. Invariants use assert. Moth has no public exception or catchable panic system. The two lanes stay distinct: Error! handles recoverable failure and assert handles impossible invariant violation.
Reflection and type introspection
Reflection, type values, runtime type IDs, compile-time type inspection and type-returning functions encourage generic metaprogramming and weaken static readability.
Higher-kinded types
Higher-kinded types, type functions, partial application and parameterized type aliases introduce a type-level abstraction language.
User const generics
User const generics beyond fixed collection capacity stay outside the language. Capacity syntax remains a small built-in collection feature, not a general type parameter system.
Source-visible memory annotation systems
Source-visible lifetime, reference-category and ownership annotation systems stay outside the language. Moth omits explicit reference types and lifetime syntax, not references themselves. The compiler tracks ownership and lifetimes internally. Source-visible lifetime parameters, temporary-reference syntax, explicit move syntax and separate borrowed and owned function signatures remain outside scope.
General lexical blocks and control-flow labels
Moth has no dedicated general lexical-block construct. block is an ordinary identifier, so block: has the same declared-region meaning as any other valid name: header. Anonymous _: blocks and brace replacements remain outside scope. Structured control flow introduces ordinary lexical scopes, while bare identifier: headers belong exclusively to declared regions.
Arbitrary statement labels, labelled break, labelled continue and goto remain outside scope. Unlabelled loop exits stay structural and target the nearest enclosing loop. Keyword-led semantic scopes such as async: remain distinct because their keyword carries language-defined behaviour.
Source-visible RC and dynamic shared ownership
Source-visible RC, retain/release, weak ownership, finalisers and unrestricted dynamic shared ownership stay outside the language. Diagnostics, common declared regions, copy and builder lifecycle roots replace source-level RC.
Retained Edge Counting is a compiler-selected physical representation for already-legal topology. It is not source syntax, not a type, and no program can name, observe or request a counter. There is no source REC.
Inferred cyclic regions
The compiler never invents a cyclic lifetime region to accept a program. Direct source-created reference cycles are legal only inside one declared region, where storage is count-free and reclaimed in bulk at declared-region exit. Cross-region cycles are invalid, and Moth has no cycle collector.
Backend-specific source legality
No backend or build profile may change which source programs are valid. Borrow validation and lifetime-topology validation run identically everywhere, and debug, GC-native and collector-free paths accept and reject exactly the same source with the same observable behaviour. There is no source-visible or project-visible no-GC mode.
Target-conditional source and backend-specific semantics
Moth excludes target, OS, architecture and backend identity from source semantics. In particular, the language has no:
target_os, target_arch, backend-name or target-name source queriesis_wasm, is_javascript or is_browser style build flags- target-conditioned imports
- target-conditioned declarations and exports
- target-conditioned receiver methods, traits or conformances
- backend-dependent language legality or observable semantics
- use of
#Config to recreate these mechanisms
The replacement is builder capability surfaces, target-contract validation, external/builder packages, and backend-owned lowering and artefact policy. Source can use a stable capability API without learning which backend implements it. Backends receive validated topology and may not reconsider source legality.
Read next