-
Notifications
You must be signed in to change notification settings - Fork 0
Value Types and Abstracts
A class can be emitted as a C++ value type rather than a reference type: new Foo(a) becomes a
stack value Foo(a) (no heap), a field/Array<Foo> is held by value (Foo/std::vector<Foo>),
member access is ., the destructor is non-virtual (no vtable — a flat value layout), and the
ownership analysis never touches it (nothing to free). This gives a value object with methods —
the hand-written-C++ idiom of a small struct-with-behaviour — letting value-heavy code (vectors,
JSON-style trees) transliterate by value instead of being reimplemented on the heap.
A value type can't do C++ polymorphism, so inheritance is rejected (slicing), as is a field holding
the class itself by value (an incomplete type — use an Array<Self>); Null<Foo> still boxes to
Foo*, as for any value type.
Two tags select a value class:
- the real hxcpp
@:stackOnlymetadata makes one that also obeys hxcpp's stack-residence rule — it may not be nested as a field or element (Hatchet flags that, steering to anabstract) — suiting genuine stack-only locals while staying portable to hxcpp; and - an
abstract Name(U)newtype (below) is a value type that nests freely, the portable way to get a value object with methods, operators, and conversions.
See the Metadata page for the full @: vs @ split.
Haxe's newtype: a value type with methods over an underlying type U, lowered to a value class
that wraps U in a synthetic __this field. Inside its methods Haxe this is the underlying value
(so this = v and this.field operate on U), and new Name(...) is value construction. This is
the portable, idiomatic way to get a value object with operators and conversions, and the nestable
value type (a field, an Array<Name>, or a recursive-by-value tree through a container).
Supported member metadata:
-
@:op(...)operator overloading, emitted as a C++ operator that forwards to the named method (so the value reads asv[k]/a + bandv.method(...), with C++ doing the operator resolution):@:op([])(one-arg read) →operator[],@:op(A op B)→ the binaryoperator op, and prefix unary@:op(-A)/!A/~A. Forms with no C++98 mapping — the two-arg@:op([])write,@:op(a.b),@:op(a()), postfix — are flagged as unsupported. -
@:to→ an implicit C++ conversion operator (@:to function toStr():String→operator std::string()), and@:from(a static factory) → a converting constructor, so the source type implicitly converts to the abstract.
Generic abstracts and @:multiType are not supported; an abstract's value-class nature means the
usual value-class caveats (no polymorphism; nests freely; Null<Name> boxes to Name*).
Related: Container Semantics for when value semantics are what you want, and
Diagnostics for the generic / @:multiType / unsupported-@:op flags.
Hatchet is licensed under the MIT License — see LICENSE. (c) 2026 Andrew Grant Lind
Getting Started
Language Support
- Declarations
- Value Types & Abstracts
- Members & Access
- Statements & Expressions
- Types & Nullability
- Conditional Compilation
- Memory Ownership
Semantics & Interop
Internals