Search code examples
pythonhaxehaxelib

How can I expose, together with my classes, the types imported from the glm Haxe lib?


I am writing a class that I will translate to both Python and C#. My code uses the nice "glm" library. Glm provides useful datatypes, e.g: Vec3.

Can I make Vec3 visible to the Python and C# users of my class? In other words, can I expose public methods using Vec3 datatypes?

Here is a sample Haxe code with a class whose public function uses the Vec3 type:

// Test execution:
// haxe -main TestGLM1 -lib glm --interp
// Translate into Python:
// haxe -main TestGLM1 -python TestGLM1.py  -lib glm 
// python3 TestGLM1.py

import glm.Vec3;
import glm.Quat;
import glm.Mat4;


class TestGLM1 {

    public function new() {
    }

    static function main() {

        // My test of the method taking 3D datatypes as input and output
        var t: TestGLM1 = new TestGLM1() ;
        var v1: Vec3 = new Vec3(1,2,3) ;
        var v2: Vec3 = new Vec3(7,8,9) ;
        t.testVecIO(v1, v2);

        trace(v1, v2);
    }

    public function testVecIO(vec_in: Vec3 , vec_out: Vec3) {
        vec_out.x = vec_in.x + vec_out.x;
        vec_out.y = vec_in.y + vec_out.y;
        vec_out.z = vec_in.z + vec_out.z;
    }
}

I would like to write a Python test like this:

from TestGLM1 import TestGLM1
from TestGLM1 import glm_Vec3

print("Python Test...")

t = TestGLM1()

v1 = glm_Vec3(1,2,3)  # Vec3()
v2 = glm_Vec3(4,5,6)  # Vec3()
t.testVecIO(v1, v2)
print(v1, v2)

print("Python done.")

However, this test fails:

ImportError: cannot import name 'glm_Vec3'

because the only class that I can see in TestGLM1.py is:

class glm_Vec3Base:
    _hx_class_name = "glm.Vec3Base"
    __slots__ = ("x", "y", "z")
    _hx_fields = ["x", "y", "z"]

    def __init__(self):
        self.z = None
        self.y = None
        self.x = None

which has both an unfriendly name and doesn't show a proper constructor.

Any advice? Thanks.


Solution

  • the only class that I can see in TestGLM1.py is glm_Vec3Base

    That's because Vec3 is an abstract type, and abstracts only exist at compile-time. The underlying type is indeed a class called Vec3Base, and if you check Vec3.hx you'll notice why it "doesn't have a proper constructor":

    class Vec3Base {
        function new() {}
    
        var x:Float;
        var y:Float;
        var z:Float;
    }
    

    You can also notice that all of Vec3's methods are declared as inline. If they weren't (you can force this by compiling with --no-inline), your Python output would have an additional class named glm__Vec3_Vec3_Impl_. It has static methods for all of Vec3's methods, since that's how abstracts work under the hood:

    A good question at this point is "What happens if a member function is not declared inline" because the code obviously has to go somewhere. Haxe creates a private class, known to be the implementation class, which has all the abstract member functions as static functions accepting an additional first argument this of the underlying type.

    In summary, due to Vec3 being implemented as an abstract, I don't think there's a convenient way to expose it to Python or C# users. Haxe-generated code in general isn't very suitable for being used like that. That's not to say there are no mechanisms to facilitate it at all. For instance, there's the @:expose metadata for the JavaScript and Lua targets.