Releases: andrewglind/hatchet
Release list
v0.3.3 — VC6-safe conversions at call sites (2026-09-22)
Release Notes
Conversion hazards at call sites, routed around in the generator rather than worked around in Haxe.
Narrowing conversions are explicit casts
A value stored into a smaller scalar than it has now says so — (uint16_t)(base + 1),
(float)(a * 0.5) — instead of relying on the implicit conversion. The conversion happens either
way (Haxe arithmetic on Int is int arithmetic and on Float is double arithmetic), so nothing
changes at runtime; it silences MSVC C4244, and it is the one lever the generator has against a VC6
/O2 miscompile in which a uint16_t narrowed from a loop-derived int takes the first
iteration's value on every iteration — correct element count, repeated values. Whether the cast
suppresses that is unconfirmed: it needs a real VC6 Release build to tell.
Applied wherever the target type is known — a call argument, a local or field initialiser or
assignment, a return, a container element, a struct-literal field — and only for genuine
narrowings: a smaller destination of the same kind, or a floating value into an integer. Literals
are written in the target type already, so they are not cast. C++ integral promotion is
accounted for: n + 1 where n is a cpp.UInt16 is an int expression, so storing it back into a
uint16_t is a narrowing and is cast.
Pushed values are bound to an element-typed local
std::vector<T>::push_back takes const T&, so an argument that is not already a T lvalue
materialises a temporary at the call site and binds the reference to that. push, insert and
unshift now bind such an argument to a named local of the element type first:
uint16_t _elem2 = (uint16_t)(base + 1);
indices.push_back(_elem2);Left inline: a literal, a plain local or this field already of the element type, a
struct/array/map literal (already hoisted into an element-typed temp), and a pointer element type
(nothing converts, and hoisting a new would disturb the ownership lowering). Alias typedefs are
looked through, so a local declared Tileset still pushes straight into an Array<Tile> with no
redundant copy.
This began as a suspected fix for the VC6 miscompile above; that diagnosis was wrong — the fault
survives it, and the narrowing is the isolated trigger. It is kept as hardening: binding the
reference to a named variable is the shape hand-written C++ would have, at no runtime cost.
Floating literals and narrowings in cpp.Float32 contexts
Every Haxe floating literal was emitted as a C++ double literal, whatever it landed in, so a
cpp.Float32 (C++ float) target narrowed at the conversion — which MSVC reports as C4305 on each
line. A literal in a float context is now emitted with the f suffix, in every position where
the target type is known: an argument to a cpp.Float32 parameter, a local or field initialiser or
assignment, a return, an Array<cpp.Float32> element, and a struct-literal field.
camera->SetPerspective(70.0f, 0.1f, 100.0f); // was 70.0, 0.1, 100.0 — C4305An expression (rather than a literal) narrowing into a float context is the C4244 counterpart,
covered by the explicit casts above — this->fx = (float)(someFloatValue);.
Arithmetic keeps Haxe's semantics: Float arithmetic is double arithmetic whatever it is assigned
to, so an operand keeps its double literal and return a * 0.5; still computes in double,
narrowing once at the end (return (float)(a * 0.5);). Suffixing the operand would silently make
the computation single-precision — a behaviour change rather than a cosmetic one. Genuine Float /
double contexts are untouched.
Install hatchet 0.3.3
Install prebuilt binaries via shell script
curl --proto '=https' --tlsv1.2 -LsSf https://github.com/andrewglind/hatchet/releases/download/v0.3.3/hatchet-installer.sh | shInstall prebuilt binaries via powershell script
powershell -ExecutionPolicy Bypass -c "irm https://github.com/andrewglind/hatchet/releases/download/v0.3.3/hatchet-installer.ps1 | iex"Download hatchet 0.3.3
| File | Platform | Checksum |
|---|---|---|
| hatchet-aarch64-apple-darwin.tar.xz | Apple Silicon macOS | checksum |
| hatchet-x86_64-apple-darwin.tar.xz | Intel macOS | checksum |
| hatchet-x86_64-pc-windows-msvc.zip | x64 Windows | checksum |
| hatchet-aarch64-unknown-linux-gnu.tar.xz | ARM64 Linux | checksum |
| hatchet-x86_64-unknown-linux-gnu.tar.xz | x64 Linux | checksum |
v0.3.2 — Member types resolve where they are declared (2026-09-17)
Release Notes
A correctness release fixing two lowering bugs that share one root cause. When a module imports
two types with the same leaf name — typically a @proxy handle and an unrelated native value
struct, such as a ui.Vertex proxy alongside a gfx.Vertex struct — Hatchet could pick the wrong
one while typing the members of the other module's types.
Fixes
-
A member's type resolves in the module that declares it. The field types of a
typedef
struct or class, a property's field type, and a method's return type were resolved in the scope
of the module using them rather than the module declaring them. -
Types recovered from a C++ spelling match the qualified name. A vector's element type or a
map's value type is recovered from its emitted spelling (std::vector<gfx::Vertex>). That lookup
used only the leaf name (Vertex), so it too could land on a same-named type in another
namespace; it now matches namespace + name exactly, falling back to the leaf name only when no
qualified match exists.
Existing code whose type names don't collide generates byte-identical output.
Install hatchet 0.3.2
Install prebuilt binaries via shell script
curl --proto '=https' --tlsv1.2 -LsSf https://github.com/andrewglind/hatchet/releases/download/v0.3.2/hatchet-installer.sh | shInstall prebuilt binaries via powershell script
powershell -ExecutionPolicy Bypass -c "irm https://github.com/andrewglind/hatchet/releases/download/v0.3.2/hatchet-installer.ps1 | iex"Download hatchet 0.3.2
| File | Platform | Checksum |
|---|---|---|
| hatchet-aarch64-apple-darwin.tar.xz | Apple Silicon macOS | checksum |
| hatchet-x86_64-apple-darwin.tar.xz | Intel macOS | checksum |
| hatchet-x86_64-pc-windows-msvc.zip | x64 Windows | checksum |
| hatchet-aarch64-unknown-linux-gnu.tar.xz | ARM64 Linux | checksum |
| hatchet-x86_64-unknown-linux-gnu.tar.xz | x64 Linux | checksum |
v0.3.1 — Static fields (2026-07-20)
Release Notes
Class static fields are now lowered as genuine class-scoped statics instead of being
mistakenly emitted as per-instance members. A scalar / String static with a literal
initializer (or none) is a plain class static — static T NAME; in the header, with an out-of-line
T Class::NAME = <literal>; definition — and reads as Class::NAME.
Otherwise the field is lowered as a Meyers singleton: a static T& NAME() accessor whose
function-local static holds the value and is initialised on the first call, read as
Class::NAME(). This is the case for any struct / container / reference-typed static (C++98
cannot constant-initialise one as a class-scope data member) and for a scalar with a non-literal
initializer (a call, new, arithmetic, …) — deferring it to first use rather than running it at
an unspecified point in the C++ static-initialisation order (the "static init order fiasco"). A
function-local static is initialised exactly once by the language, so no guard flag is needed;
when the initializer builds a temporary (e.g. an array), that setup is folded into a one-off
_init_* helper so it too runs once. A final field returns const T& (it is immutable); a var
stays writable through the returned reference. Reads resolve correctly whether written bare inside
the class or qualified (Class.NAME) from elsewhere.
Because the accessor-vs-data-member choice is driven by the field's type, a consuming
extern / @proxy binding — which carries no initializer — reads the field the same way the
producing class emits it: a struct-typed static bound through an extern is called
(native::Class::NAME()), matching the native Meyers accessor, while a scalar static final stays
a plain data-member read.
Install hatchet 0.3.1
Install prebuilt binaries via shell script
curl --proto '=https' --tlsv1.2 -LsSf https://github.com/andrewglind/hatchet/releases/download/v0.3.1/hatchet-installer.sh | shInstall prebuilt binaries via powershell script
powershell -ExecutionPolicy Bypass -c "irm https://github.com/andrewglind/hatchet/releases/download/v0.3.1/hatchet-installer.ps1 | iex"Download hatchet 0.3.1
| File | Platform | Checksum |
|---|---|---|
| hatchet-aarch64-apple-darwin.tar.xz | Apple Silicon macOS | checksum |
| hatchet-x86_64-apple-darwin.tar.xz | Intel macOS | checksum |
| hatchet-x86_64-pc-windows-msvc.zip | x64 Windows | checksum |
| hatchet-aarch64-unknown-linux-gnu.tar.xz | ARM64 Linux | checksum |
| hatchet-x86_64-unknown-linux-gnu.tar.xz | x64 Linux | checksum |
v0.3.0 — `@sink` in more positions (2026-07-13)
Release Notes
@sink means what it always has — ownership leaves here; this scope does not free the value —
but until now it could only be written on a parameter. This release lets you write it where
the hand-off actually happens: on a call argument and on a local declaration.
Metadata is allowed on any expression
Haxe permits @meta expr on any expression, but Hatchet's expression parser had no arm for a
leading metadata token. Expression-position metadata now parses and is transparent to
type and value — it changes nothing about how the wrapped expression lowers. Metadata other than
@sink is carried but inert, matching hxcpp, which ignores expression-position metadata at the
C++ target.
@sink on a call argument and a local declaration
The same transfer semantics as a @sink parameter, now available at two more sites:
- A
@sink new X(...)call argument is emitted inline — not hoisted into a scope-owned
local that the caller deletes. - A
@sink localcall argument (an already-owned local) has its scope-closedelete
dropped, transferring the object to the callee. - A
@sink var x = new X(...)local declaration suppresses the scope-closedeleteofx
entirely — the inverse of@delete var— for when ownership is handed off with no single call
to attach the marker to.
@sink is an assertion that ownership leaves the current scope, so it applies even
when the destination is opaque to Hatchet (an @:native class, or a hand-off the analysis cannot
follow) — it overrides the escape analysis. If nothing actually takes ownership the result is a
leak, never a double-free. @sink on a value local or argument (nothing to hand off) is a
no-op and warns.
Install hatchet 0.3.0
Install prebuilt binaries via shell script
curl --proto '=https' --tlsv1.2 -LsSf https://github.com/andrewglind/hatchet/releases/download/v0.3.0/hatchet-installer.sh | shInstall prebuilt binaries via powershell script
powershell -ExecutionPolicy Bypass -c "irm https://github.com/andrewglind/hatchet/releases/download/v0.3.0/hatchet-installer.ps1 | iex"Download hatchet 0.3.0
| File | Platform | Checksum |
|---|---|---|
| hatchet-aarch64-apple-darwin.tar.xz | Apple Silicon macOS | checksum |
| hatchet-x86_64-apple-darwin.tar.xz | Intel macOS | checksum |
| hatchet-x86_64-pc-windows-msvc.zip | x64 Windows | checksum |
| hatchet-aarch64-unknown-linux-gnu.tar.xz | ARM64 Linux | checksum |
| hatchet-x86_64-unknown-linux-gnu.tar.xz | x64 Linux | checksum |
v0.2.9 — Type-resolution & arithmetic fixes (2026-07-11)
Release Notes
A correctness release fixing three lowering bugs. A Module.func() call that targets a
module-level function no longer emits a bogus class qualifier; a typedef alias is now fully
transparent — it takes on the shape of whatever it names, everywhere; and mixed Int/Float
arithmetic infers Float, so a var bound to it no longer truncates. The fixed-C-array
"fill" detection added during the raw-pointer work — undocumented since v0.2.8 — is removed.
Fixes
-
Module.func()for a module-level function drops the class qualifier. Haxe lets you
call a module-level function through the module name —Palette.mix(a, b)wheremixis
declared at the top ofPalette.hx, not a member of the primary classPalette. Such a
function lowers to a namespace free function, so Hatchet no longer emits the non-existent
Palette::mix(...); it emitsmix(...)(namespace-qualified as needed, e.g.util::mix).
A genuine static member (Registry.slot(...)) still uses scope resolution,
Registry::slot(...). -
A
typedefalias is fully transparent. A Haxetypedef X = Yis the same type asY
everywhere, but Hatchet made shape decisions (pointer-vs-value, reference-vs-container,
by-value-vs-const&, member dispatch) from the alias name rather than its target — so an
alias only behaved correctly for a couple of shapes. Aliases are now resolved through
before every such decision, while the alias name is kept in the emitted spelling. Fixes,
across every alias shape:typedef Color = cpp.UInt32(primitive) — passed by value (optional gets a default),
notconst Color&or aColor*pointer.typedef Panel = Widget(a class) — aPanel*with->dispatch, not a sliced
by-valuePanel; methods/fields resolve through the alias (panel.tag()→w->tag()).typedef Ints = Array<Int>(container) — passedconst Ints&(Haxe's shared-reference
semantics), not a silent by-value copy.typedef Vertex = Pt(a{ … }struct) —const Vertex&, with working field access
(v.x).typedef Name = String— keeps theconst Name&optimization; an optional?n:Name
defaults to"".Null<Ptr>wheretypedef Ptr = cpp.RawPointer<T>— a single pointer, no longerPtr*
(a double pointer). A custom iterator reached through an alias now iterates transparently.
-
Mixed Int/Float arithmetic infers
Float. An arithmetic operator's result type was
taken from the left operand alone, sointField / floatField(and+,-,*,%) was
inferredInt. Avar r = intField / floatFieldwas then declaredintand truncated the
doublethe expression actually computes. Arithmetic now promotes toFloatwhen either
operand is aFloat, matching C++'s (and Haxe's) usual arithmetic conversions. Int-only
arithmetic, shifts, and the existingInt / Int → Floatdouble-division cast are unchanged.
Removed: fixed-C-array "fill" detection
The raw-pointer work briefly special-cased cpp.Pointer.ofArray(...).raw written into fixed
C-array storage, warning that a bare .raw cannot fill a native T[N]. That handling was
de-documented in v0.2.8 and is now removed entirely: cpp.Pointer.ofArray(a).raw is simply
the address of the first element (&(a)[0]), with no position-dependent diagnostics. The
general .raw intrinsics (cpp.Pointer.fromStar(x).raw, cpp.Pointer.ofArray(a).raw) are
unchanged.
Install hatchet 0.2.9
Install prebuilt binaries via shell script
curl --proto '=https' --tlsv1.2 -LsSf https://github.com/andrewglind/hatchet/releases/download/v0.2.9/hatchet-installer.sh | shInstall prebuilt binaries via powershell script
powershell -ExecutionPolicy Bypass -c "irm https://github.com/andrewglind/hatchet/releases/download/v0.2.9/hatchet-installer.ps1 | iex"Download hatchet 0.2.9
| File | Platform | Checksum |
|---|---|---|
| hatchet-aarch64-apple-darwin.tar.xz | Apple Silicon macOS | checksum |
| hatchet-x86_64-apple-darwin.tar.xz | Intel macOS | checksum |
| hatchet-x86_64-pc-windows-msvc.zip | x64 Windows | checksum |
| hatchet-aarch64-unknown-linux-gnu.tar.xz | ARM64 Linux | checksum |
| hatchet-x86_64-unknown-linux-gnu.tar.xz | x64 Linux | checksum |
v0.2.8 — C-style arrays & raw-pointer interop (2026-07-02)
Release Notes
A native-interop release: hxcpp's raw-pointer types now lower and the .raw pointer
intrinsics are recognised. Dynamic / Any become the faithful spelling for an opaque
void* and {} for that role is deprecated. A latent cast-ascription miscompile is fixed.
Internally the parser and code generator were split into focused modules with a reorganised
test suite. The @:decl / @:abi deprecation warnings added in v0.2.7 are removed (those
metadata are now silently parsed-and-ignored).
hxcpp raw-pointer interop types lower to C pointers
The hxcpp pointer interop family now maps to native C++ pointers, joining cpp.Pointer<T>:
cpp.RawPointer<T>andcpp.Star<T>→T*cpp.ConstStar<T>→const T*cpp.Void→void, socpp.RawPointer<cpp.Void>/cpp.Star<cpp.Void>givevoid*
These resolve at every use site (field, parameter, local, return) and index as C pointers
(p[i]), so a Haxe binding to a native struct with a T* / const T* / void* member
transpiles faithfully.
Dynamic / Any are the opaque void*; {} for that role is deprecated
Dynamic and Any in an emitted position now erase to void* — an opaque pointer that
carries anything (Any is abstract Any(Dynamic), so both are Dynamic-backed at runtime).
Dynamic also keeps its existing @:overload-marker role.
Because Dynamic (opaque value) and cpp.RawPointer<cpp.Void> (opaque pointer) are now the
faithful spellings, using the empty structure {} as a void* type is deprecated. It
still lowers to void* so existing sources keep working, but now emits a non-fatal
deprecation warning naming the replacement; the void* lowering will be removed in a future
release. (In hxcpp {} is a structure object, not a raw pointer — this was a Hatchet-ism.)
.raw pointer intrinsics
The cpp.Pointer .raw accessors used to satisfy hxcpp are recognised and lowered:
cpp.Pointer.fromStar(x).raw— the developer's intent to viewxas a raw pointer:
emitsxwhenxis already a pointer, else takes its address&(x). This is the
supported way to accept a?data:Dynamicargument and store it asvoid*
(this.data = cpp.Pointer.fromStar(data).raw;).cpp.Pointer.ofArray(a).raw— a pointer to the first element,&(a)[0].
Reference semantics: mutable-reference getters, const-ref parameter writes
- Write-restricted getters return
T&. A generated getter for a container
(std::vector/std::map) or value-struct field now returns a mutable reference (T&)
rather than aconst Tcopy, so Haxe's reference-type mutation through a getter works:
obj.items[k] = v;and in-place struct mutation compile and take effect. - Assigning through a
const&value-struct parameter is a hard error. A value-struct
parameter lowers toconst T&; writing through it is now reported up front instead of
emitting non-compiling C++.
Fixes
- Array-literal cast-ascription element type.
([...] : Array<cpp.UInt8>)built a
std::vector<int>and then assigned it to astd::vector<uint8_t>— a type clash that
would not compile. A container ascription now pins the element type through the literal, so
the vector is built asstd::vector<uint8_t>directly.
@:decl / @:abi deprecation warnings removed
v0.2.7 renamed the export behaviours to @libexport / @cexport and made @:decl / @:abi
emit a deprecation warning. Those warnings are now removed: @:decl / @:abi are Haxe
inbound-only metadata and are purely parsed-and-ignored, with no diagnostic.
Internal
- The monolithic
parser.rsandcodegen/mod.rswere split into focused submodules
(parser/{decls,expr,stmt,types},codegen/{header,amalgam},codegen/source/{control,loops}),
and the singletests/source_codegen.rswas reorganised into topic-scoped files
(codegen_core,codegen_control,codegen_intrinsics,codegen_ownership,codegen_proxy,
codegen_rawptr,codegen_types) sharing atests/commonhelper module. No behavioural change.
Install hatchet 0.2.8
Install prebuilt binaries via shell script
curl --proto '=https' --tlsv1.2 -LsSf https://github.com/andrewglind/hatchet/releases/download/v0.2.8/hatchet-installer.sh | shInstall prebuilt binaries via powershell script
powershell -ExecutionPolicy Bypass -c "irm https://github.com/andrewglind/hatchet/releases/download/v0.2.8/hatchet-installer.ps1 | iex"Download hatchet 0.2.8
| File | Platform | Checksum |
|---|---|---|
| hatchet-aarch64-apple-darwin.tar.xz | Apple Silicon macOS | checksum |
| hatchet-x86_64-apple-darwin.tar.xz | Intel macOS | checksum |
| hatchet-x86_64-pc-windows-msvc.zip | x64 Windows | checksum |
| hatchet-aarch64-unknown-linux-gnu.tar.xz | ARM64 Linux | checksum |
| hatchet-x86_64-unknown-linux-gnu.tar.xz | x64 Linux | checksum |
v0.2.7 — Export metadata `@libexport` / `@cexport` (2026-06-26)
Release Notes
A metadata-correctness release with a breaking rename (deprecation path is provided).
Haxe-faithful @:decl / @:abi; export behaviours move to @libexport / @cexport
Hatchet repurposed @:decl and @:abi for outbound (producing) C++:
@:decl decorated a class for shared-library export (<PREFIX>_CLASS), and @:abi
turned a free function into a global extern "C" export. The Haxe compiler
source shows both metadata are inbound-only and unrelated to that, So the two
Hatchet behaviours have been renamed to dedicated custom metadata,
and @:decl / @:abi are now parsed and ignored.
Using @:decl / @:abi tokens now emits a non-fatal deprecation
warning naming the replacement.
Bare @:decl / @:abi now have no effect beyond the warning, and will be removed in a future release.
Migration steps
- replace
@:declon an exported class with@libexport - replace
@:abion an exported function with@cexport
Install hatchet 0.2.7
Install prebuilt binaries via shell script
curl --proto '=https' --tlsv1.2 -LsSf https://github.com/andrewglind/hatchet/releases/download/v0.2.7/hatchet-installer.sh | shInstall prebuilt binaries via powershell script
powershell -ExecutionPolicy Bypass -c "irm https://github.com/andrewglind/hatchet/releases/download/v0.2.7/hatchet-installer.ps1 | iex"Download hatchet 0.2.7
| File | Platform | Checksum |
|---|---|---|
| hatchet-aarch64-apple-darwin.tar.xz | Apple Silicon macOS | checksum |
| hatchet-x86_64-apple-darwin.tar.xz | Intel macOS | checksum |
| hatchet-x86_64-pc-windows-msvc.zip | x64 Windows | checksum |
| hatchet-aarch64-unknown-linux-gnu.tar.xz | ARM64 Linux | checksum |
| hatchet-x86_64-unknown-linux-gnu.tar.xz | x64 Linux | checksum |
v0.2.6 — Scalar type ascriptions (2026-06-25)
Release Notes
A correctness release: a scalar-numeric type-check expression now emits a real C++ cast, so the ascribed
arithmetic type is honoured at the value level instead of being silently narrowed. No breaking changes.
(expr : Type) pins the C++ arithmetic type
A type-check / ascription expression (expr : Type) was treated as a pure compile-time hint: the inner
expression was emitted unchanged and only its internal type was relabelled. For a scalar-numeric target
that lost the developer's intent — (Std.parseFloat(s) : cpp.Float32) still emitted a double (atof),
and (0.0 : cpp.Float32) a double literal, so a cpp.Float32-returning function silently narrowed its
result on return.
When the ascribed type is a built-in arithmetic scalar (Int, Float, Single/cpp.Float32, Bool,
the fixed-width integers, …), Hatchet now emits an explicit C cast to that type, matching what hxcpp
generates:
function toFloat(s:String):cpp.Float32 {
return (s != null) ? (Std.parseFloat(s) : cpp.Float32) : (0.0 : cpp.Float32);
}now lowers both arms to float — ((float) atof(s.c_str())) and ((float) 0.0) — so the ternary type
matches the float return with no implicit narrowing.
Non-scalar ascriptions keep the existing no-op behaviour: a class-typed null ((null : Widget)), an
empty container literal (([] : Array<Int>)), or a String adopt the ascribed type without an unwanted
or unbuildable cast.
Install hatchet 0.2.6
Install prebuilt binaries via shell script
curl --proto '=https' --tlsv1.2 -LsSf https://github.com/andrewglind/hatchet/releases/download/v0.2.6/hatchet-installer.sh | shInstall prebuilt binaries via powershell script
powershell -ExecutionPolicy Bypass -c "irm https://github.com/andrewglind/hatchet/releases/download/v0.2.6/hatchet-installer.ps1 | iex"Download hatchet 0.2.6
| File | Platform | Checksum |
|---|---|---|
| hatchet-aarch64-apple-darwin.tar.xz | Apple Silicon macOS | checksum |
| hatchet-x86_64-apple-darwin.tar.xz | Intel macOS | checksum |
| hatchet-x86_64-pc-windows-msvc.zip | x64 Windows | checksum |
| hatchet-aarch64-unknown-linux-gnu.tar.xz | ARM64 Linux | checksum |
| hatchet-x86_64-unknown-linux-gnu.tar.xz | x64 Linux | checksum |
v0.2.5 — Haxe-aligned `untyped` & `cpp.ConstCharStar` (2026-06-24)
Release Notes
A correctness release: untyped now matches Haxe's actual semantics, raw C++ injection moves to the
__cpp__ intrinsic it belongs to, and the cpp.ConstCharStar interop type lowers. No breaking changes
for the supported untyped idiom — see below.
untyped and __cpp__ aligned with Haxe
Previously untyped <expr> was a lexical construct: it sliced the raw source to the end of the
statement and emitted it verbatim, bypassing all transpilation. That conflated two separate Haxe
mechanisms and meant the canonical escape hatch untyped __cpp__("…") was broken (it emitted the literal
text __cpp__("…")).
The two concepts are now distinct, matching Haxe:
untyped <expr>is the typer escape hatch. The operand is parsed and transpiled like any other
expression; the only effect is that its static type is treated as opaque (Dynamic), so type-driven
checks relax. It binds as a normal unary prefix rather than swallowing to the next;.__cpp__("…", a, b)(Haxe'scpp.Syntax.code) is the raw-injection intrinsic. The format string
is emitted verbatim, with{0},{1}, … placeholders replaced by the transpiled arguments — so
real Hatchet expressions can be spliced into hand-written C++ (__cpp__("::fmaxf({0}, {1})", v, lo)→
::fmaxf(v, lo)). Because Hatchet only ever targets C++, the call is recognised with or without the
untypedwrapper Haxe needs to silence its unknown-identifier error.
The common existing idiom untyped someCName(args) is unaffected: the call is now transpiled normally and
produces identical output.
cpp.ConstCharStar lowers to const char*
hxcpp's cpp.ConstCharStar interop type now maps to const char* (joining cpp.StdString → std::string
and the rest of the primitive mappings).
Install hatchet 0.2.5
Install prebuilt binaries via shell script
curl --proto '=https' --tlsv1.2 -LsSf https://github.com/andrewglind/hatchet/releases/download/v0.2.5/hatchet-installer.sh | shInstall prebuilt binaries via powershell script
powershell -ExecutionPolicy Bypass -c "irm https://github.com/andrewglind/hatchet/releases/download/v0.2.5/hatchet-installer.ps1 | iex"Download hatchet 0.2.5
| File | Platform | Checksum |
|---|---|---|
| hatchet-aarch64-apple-darwin.tar.xz | Apple Silicon macOS | checksum |
| hatchet-x86_64-apple-darwin.tar.xz | Intel macOS | checksum |
| hatchet-x86_64-pc-windows-msvc.zip | x64 Windows | checksum |
| hatchet-aarch64-unknown-linux-gnu.tar.xz | ARM64 Linux | checksum |
| hatchet-x86_64-unknown-linux-gnu.tar.xz | x64 Linux | checksum |
v0.2.4 — Typedef-alias containers & method visibility (2026-06-23)
Release Notes
A correctness release: escape analysis now sees through typedef aliases to the containers they name,
and class methods land in the right C++ visibility section. No breaking changes.
Escape analysis sees through typedef alias containers
Escape analysis now peels typedef aliases (typedef Matrix = Array<Row>) before counting Array nesting,
so aliased containers are tracked at their true depth. A local container of owned (new-d) elements that
flows into an owned alias-typed field is recognised as escaping and is no longer freed at end of scope.
A nullable alias container (Null<Indicies> where typedef Indicies = Array<Int>) also keeps its
pointer-ness through alias resolution, so container methods on it dereference correctly — indices.map(…)
lowers to (*indices).size() / (*indices)[i].
Class methods lower to the correct C++ visibility
A class method lands in the C++ public section only when it is explicitly public; everything else —
including Haxe's default (no modifier) access, which is private — lowers to protected, mirroring how
fields are grouped.
Custom property accessors are the exception: a get_x / set_x backing a public property is promoted to
public even when the accessor itself is private, keeping it at least as visible as the property it serves.
Install hatchet 0.2.4
Install prebuilt binaries via shell script
curl --proto '=https' --tlsv1.2 -LsSf https://github.com/andrewglind/hatchet/releases/download/v0.2.4/hatchet-installer.sh | shInstall prebuilt binaries via powershell script
powershell -ExecutionPolicy Bypass -c "irm https://github.com/andrewglind/hatchet/releases/download/v0.2.4/hatchet-installer.ps1 | iex"Download hatchet 0.2.4
| File | Platform | Checksum |
|---|---|---|
| hatchet-aarch64-apple-darwin.tar.xz | Apple Silicon macOS | checksum |
| hatchet-x86_64-apple-darwin.tar.xz | Intel macOS | checksum |
| hatchet-x86_64-pc-windows-msvc.zip | x64 Windows | checksum |
| hatchet-aarch64-unknown-linux-gnu.tar.xz | ARM64 Linux | checksum |
| hatchet-x86_64-unknown-linux-gnu.tar.xz | x64 Linux | checksum |