Nate C-K
Nate C-K

Reputation: 5932

Calling Lua static functions from Haxe code

Brief version

How can I write Haxe code that will generate Lua code that makes static function calls instead of using the instance method call syntax?

Long version

I have a Haxe program that generates Lua code. I'm running this Lua code on LÖVE, where the runtime exposes various functions using Lua tables as namespaces. These functions are mostly intended to be called in a static manner, like so:

love.graphics.setColor(r, g, b)

Unfortunately, Haxe's Lua code generation seems to assume that all Lua function calls are invoking instance methods, so the code it generates uses Lua's method calling syntax, like this:

love.graphics:setColor(r, g, b)

I've tried various ways of calling this function. I've only found one that works:

class Love {
  static public var graphics: Graphics = new Graphics();
}

class Graphics {
  public function new() {}
  public function setColor(r: Int, g: Int, b: Int) {
    var fn = untyped love.graphics.setColor;
    fn(r, g, b);
  }
}

I can invoke this in Haxe like so:

Love.graphics.setColor(r, g, b);

This works fine, but it's inelegant, so I'm wondering if there's a better way to do it. I suspect it may also have some tiny performance cost, though I'm not particularly worried about that, and LuaJIT might be smart enough to optimize the intermediate variable away in any case. Mostly I just want a cleaner way to write this wrapper code.

It seems like Haxe's extern functionality might be the answer here, but there is currently no Lua-specific documentation of how to use it and I can't figure out how to apply it here.

Here are some examples of code that did not work (they generated instance method calls instead of static calls):

public function setColor(r: Int, g: Int, b: Int) {
    (untyped love.graphics.setColor)(r, g, b);
}

var _setColor = untyped love.graphics.setColor;
public function setColor(r: Int, g: Int, b: Int) {
    _setColor (r, g, b);
}

Upvotes: 3

Views: 950

Answers (1)

Gama11
Gama11

Reputation: 34138

Indeed, you can accomplish this with @:luaDotMethod metadata on an extern. From haxe --help-metas:

Indicates that the given extern type instance should have dot-style invocation for methods instead of colon.

Here's an example:

class Main {
    public static function main() {
        Love.graphics.setColor(0, 0, 0);
    }
}

@:native("love")
extern class Love {
    static var graphics(default, null):Graphics;
}

@:luaDotMethod
extern class Graphics {
    function setColor(r:Int, g:Int, b:Int):Void;
}

This generates the following Lua code:

Main.main = function() 
  love.graphics.setColor(0, 0, 0);
end

Alternatively, you could accomplish the same by declaring setColor() as a static function, which might be more natural from a Haxe perspective:

class Main {
    public static function main() {
        love.Graphics.setColor(0, 0, 0);
    }
}
package love;

@:native("love.graphics")
extern class Graphics {
    static function setColor(r:Int, g:Int, b:Int):Void;
}

Btw, there is already a library with Love2D externs on Haxelib called hx-love2d. Not sure how updated or complete it is though. Here, setColor() seems to be defined as GraphicsModule.setColor() (in a love.graphics package).

Upvotes: 3

Related Questions