12.6.8.2 Pointer Types

C and COM APIs require you to pass context objects into functions as C struct cannot contain functions, these contexts are simply pointers to a struct. In these APIs the user is not responsible for directly allocating the context (e.g. using malloc). Instead, the API provides some kind of alloc and free function to perform these acts for you. Due to the ubiquity of these APIs, pointer type extern classes were designed representing these patterns. They share many similarities to the value type extern but represent a type which is passed by reference (i.e. a pointer) instead of a type which is passed by value.

struct ctx {};

ctx* lib_alloc_ctx();
void lib_free_ctx(ctx* pCtx);

int lib_foo(ctx* pCtx);
@:semantics(value)
@:cpp.PointerType({ type : "ctx" })
extern class Ctx {}

extern class Lib {
    @:native("lib_alloc_ctx")
    extern function allocCtx():Ctx;

    @:native("lib_free_ctx")
    extern function freeCtx(ctx:Ctx):Void;

    @:native("lib_foo")
    extern function foo(ctx:Ctx):Int;
}

function main() {
    final ctx = Lib.allocCtx();
    final val = Lib.foo(ctx);

    trace(val);

    Lib.freeCtx(ctx);
}

There are not currently any flags available for pointer type externs.

Details

Constructors

Since pointer types are designed to be allocated by library functions, they cannot have constructors or be manually constructed. Adding a constructor to a pointer type extern will generate a compiler error (CPP0004).

@:semantics(value)
@:cpp.PointerType
extern class Ctx {
    function new():Void; // CPP0004
}

You are allowed to initialise a variable of a cpp.PointerType extern to null.

@:semantics(value)
@:cpp.PointerType
extern class Ctx {}

function main() {
    final ctx : Ctx = null;
}
Comparison

Pointer types are compared by reference, i.e. the pointer addresses are compared, any comparison operators defined on the externed type are not used.

Nullability

Unlike value type externs, pointer type externs can be null.

Pointer to Pointer

Like value type externs, pointer type externs also require the value semantics metadata. This allows pointer type externs to easily support the pointer to pointer pattern for allocation and destruction.

struct ctx {};

void lib_alloc_ctx(ctx** pCtx);
void lib_free_ctx(ctx** pCtx);
@:semantics(value)
@:cpp.PointerType({ type : "ctx" })
extern class Ctx {}

extern class Lib {
    @:native("lib_alloc_ctx")
    extern function allocCtx(ctx:haxe.extern.AsVar<Ctx>):Void;

    @:native("lib_free_ctx")
    extern function freeCtx(ctx:haxe.extern.AsVar<Ctx>):Void;
}

function main() {
    final source : Ctx = null;
    final copy = source;

    Lib.allocCtx(source);
}

After the Lib.allocCtx call source will not be null as it will have the allocated Ctx placed in the pointer. However, copy will still be null due to value semantics still being used. Pointer types can also decay to void** which is often used in C and C++ apis.

Pointer Interop

Pointer type externs can also interop with the existing pointer types in the cpp package. It is important to note, however, that a pointer to a pointer type extern is a double pointer. e.g. cpp.RawPointer<Foo> where Foo is a pointer type extern gets generated as Foo**, not Foo*.