Opaque
A nominal, branded handle to a value the engine owns and manages — a GUI node, a texture, a render target, a physics body, a socket, and so on: hold it and pass it back to the API, but never inspect or construct it. You get one back from an engine function, keep it in a variable, and pass it to the other functions that act on that resource; treat it as an opaque ticket, meaningful to the engine, not a value you read or assemble yourself.
Why a dedicated type? Each kind of handle is its own brand, so the compiler
keeps them apart: Opaque<"node"> and Opaque<"texture"> are different
types, and passing a texture where a node is expected is a compile error,
exactly as a wrong primitive would be. The brand is a phantom unique symbol
property that lives only in the type system and is erased at transpile — at
runtime the value is just the engine's userdata. Because the symbol is never
exported, your code cannot fabricate a handle or inspect or construct one; the
engine API is the only source.
The handle kinds modeled today:
- GUI & rendering:
Opaque<"node">,Opaque<"texture">,Opaque<"render_target">,Opaque<"constant">,Opaque<"constant_buffer"> - Resources & buffers:
Opaque<"resource">,Opaque<"buffer">,Opaque<"bufferstream"> - Sockets:
Opaque<"client">,Opaque<"server">,Opaque<"master">,Opaque<"connected">,Opaque<"unconnected"> - Box2D physics:
Opaque<"b2Body">,Opaque<"b2World"> - Generic:
Opaque<"userdata">
Handles always come back from the engine — for instance:
const node = gui.get_node("button"); // Opaque<"node">
const rt = render.render_target("rt", opts); // Opaque<"render_target">
const cb = render.constant_buffer(); // Opaque<"constant_buffer">
const buf = resource.load_buffer(path); // Opaque<"buffer">
const stream = buffer.get_stream(buf, "rgb"); // Opaque<"bufferstream">
const world = b2d.get_world(); // Opaque<"b2World">
const [conn] = socket.tcp(); // a "master" socket handle
function update(self: ...) {} // self is Opaque<"userdata">
Contrast with a LuaTable alias, which says the opposite — "inspect freely,
the shape just isn't modeled." An Opaque says "do not look inside; this
value is meaningful only to the engine."