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 closures or function values
General closures 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 trait objects
Trait objects 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.
The pattern
Each excluded feature has a Moth replacement that is more constrained and more explicit. The language trades generality for clarity.
The following surfaces are intentionally outside Moth's language design scope. A feature listed here shouldn't be implemented unless the language philosophy is explicitly changed first.
Macros and 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 are the constrained compile-time surface.
General closures and function values
General closures, anonymous function values, generic function values and higher-order polymorphism add broad function-value semantics and solver pressure. Reactivity is the constrained UI-oriented mechanism intended to cover many closure-heavy template cases.
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 or specialised conformance requires coherence and specialisation rules outside Moth's simplicity target. Structural conformance must not silently imply conformance. Type must TRAIT stays explicit.
Constraint extensions
Type-set constraints, union constraints, underlying-type constraints and user-defined numeric or operator constraints make generic bounds a constraint sublanguage. Generic bounds name traits only.
Operator overloading
Operators stay compiler-owned and predictable. No source-visible operator overloading.
Source-authored receiver extensions
Source-authored receiver methods for builtins, imported types, dependency package types, external opaque types or types declared in another file are rejected. Receiver methods belong only to the same file as their nominal receiver type.
User-defined map semantics
User-defined HASHABLE, custom map hashers or comparers and user-defined keys for builtin maps are rejected. Builtin map syntax stays scalar-keyed. More sophisticated maps belong in packages as ordinary structs.
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.
Exceptions and invariant assertions
Expected failures use Error!. Invariants use assert. No public exception system. The two lanes stay distinct: Error! handles recoverable failure, assert handles impossible invariant violation.
Reflection and type introspection
Reflection, 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 type application and parameterised type aliases introduce a type-level abstraction language.
Const generics
User const generics beyond fixed collection capacity are rejected. 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 RC and dynamic shared ownership
Source-visible RC, retain/release, weak ownership, finalisers and unrestricted dynamic shared ownership are outside language design scope. Internal backend RC remains allowed for already-legal topology. Diagnostics, common-owner groups, copy and builder lifecycle roots replace source-level RC.
Backend-specific semantics leaking into source
Backend-specific observable semantics must not leak into the language. Source semantics stay backend-neutral. Backends receive validated topology and may not reconsider source legality.
Read next