Harnessing Haxe’s @:enum for Cross‑Platform Performance
Use Haxe’s @:enum to turn enums into plain integers, boosting performance across JavaScript and native targets. Learn how to write, compile, and benchmark a state machine with this feature, and understand its trade‑offs.
02 Sept 2025, 10:29 UTC

Why @:enum Matters
When you write a Haxe program that targets both JavaScript and a native language like C++, you often hit a performance wall in state machines, event dispatch, or rendering loops. The culprit is usually the enum representation. Haxe’s @:enum metadata turns an enum into a plain integer at compile time, eliminating the overhead of boxing and allowing the target compiler to generate tight switch statements. The result is a 2–3× speed boost in hot paths and a smaller memory footprint on native targets.
What @:enum Does Under the Hood
Ordinary Haxe enums are objects that carry a tag and optional data. In JavaScript they become objects with a __name property, and in C++ they compile to a struct with a __name field. The @:enum annotation tells the Haxe compiler to treat the enum as a simple integer value:
@:enum
enum Direction {
North;
East;
South;
West;
}
When compiled to JavaScript, the enum values become numeric constants:
var Direction = {
North: 0,
East: 1,
South: 2,
West: 3
};
In C++ the compiler emits a native enum:
#ifndef Direction_h
#define Direction_h
enum Direction {
North = 0,
East = 1,
South = 2,
West = 3
};
#endif
Concrete Example: A State Machine
Consider a simple traffic light that cycles through three states. Using @:enum lets us write the same logic once and keep the runtime efficient on all targets.
@:enum
enum LightState {
Red;
Yellow;
Green;
}
class TrafficLight {
var state:LightState;
public function new() { state = LightState.Red; }
public function next() {
switch (state) {
case LightState.Red: state = LightState.Green;
case LightState.Yellow: state = LightState.Red;
case LightState.Green: state = LightState.Yellow;
}
}
}
Compile to JavaScript:
haxe -main TrafficLight -js out.js
Inspect out.js – the LightState constants are plain numbers, and the switch becomes a classic switch on integers. The generated code runs in a fraction of the time compared to a boxed enum.
Trade‑Offs and Limitations
- No per‑value data:
@:enumenums cannot carry extra fields or methods. If you need a value to hold a string or a function, drop the annotation. - Serialization: JavaScript objects are not automatically serializable to JSON. You’ll need to convert the integer back to a string or use a mapping table.
- Target differences: The integer values are stable across targets if you explicitly assign them. Without explicit values, the compiler may assign different constants in C++ vs. JavaScript, leading to subtle bugs when exchanging data between targets.
- Debugging: In a debugger, the enum appears as an integer, which can be confusing if you’re used to seeing named tags.
Practical Checklist
- Define the enum with
@:enumand assign explicit integer values if you’ll serialize or cross‑talk with external systems. - Keep the enum values simple; avoid attaching methods or data.
- When serializing to JSON, map the integer to a string or use a helper function.
- Use
haxe -interpto confirm the enum values at runtime:haxe -interp -main Test. - Benchmark critical loops in both JavaScript and native targets to verify the performance benefit.
Conclusion
Haxe’s @:enum is a lightweight tool that lets you write clean, type‑safe code once and benefit from the speed of native integers on every target. It’s ideal for state machines, event types, and other scenarios where the enum value is the only data. Just remember the constraints: no per‑value data, careful serialization, and explicit value assignment for cross‑platform consistency.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.