inline Rectangle RectangleMake(int x, int y, int w, int h) { return {x,y,w,h}; }
inline cpp::Struct<Rectangle> RectangleWrap(const Rectangle &rect) { return rect; }
inline void RectanglePrint(const Rectangle &rect) { printf("rect %d,%d %dx%d\\n", rect.x, rect.y, rect.width, rect.height ); }
')
class Test
{
public static function main()
{
var r:Rectangle = Rectangle.make(1,2,3,4);
trace("Width " + r.width);
Rectangle.print(r);
// Dynamic will not work on 'raw' Struct - must be wrapped:
//trace("Rect " + r);
var w = r.wrap();
trace("Rect " + w);
trace("Width " + w.width);
// Can still pass wrapped off to something that wants a 'Rectangle' since it inherits
Rectangle.print(w);
}
}
I've use the "headerCode" meta to allow testing from a single file, but you would typically put this stuff in a separate file.
So the trick is to make a native static function to so the work. This allows haxe to do type checking etc. you could also make an "Rectangle.empty" extern function. If you are using c++, you can make a "operator Rectangle = null" function, and use "var x:Rectangle = null;" But with type inference, "var x=Rectangle.empty()" is only marginally longer, but more descriptive.
If you are doing this, you are bound to run into the problem of passing these native rectangles via Dynamic as some stage (eg, as member variables). The solution here is to wrap the Rectangle with the native "cpp::Struct" template, like in the example. You can then differentiate between wrapped and native rectangles. You can generally use a wrapped rectangle in all the places you would use the normal rectangle, since it auto-casts and if use the inheritance pattern above.
You could be tricky and use abstracts to remove the need for "wrap()" call, and possibly allow "{1,2,3,4}" syntax via macros, but I would get the basics going first.