Haxe 4.2.1 で python コードを出力した結果

4 min read読了の目安(約4400字

概要

Python を最近触り始めたところコードブロックがインデント基準というのが個人的に気に入らず、スーパーセットを探したところ Haxe "ハックス(Youtube調べ)" (https://haxe.org/) を見つけた。
バイトコードを吐くのではなく、Python のソースにトランスパイルできるので、既存の Python コードとキメラ合体できるのでは?と思い触ってみた。

環境

Haxe: 4.2.1

コード1

Haxe

Main.hx
class Main {
  static public function main():Void {
    trace("Hello World");
  }
}

ファイル名はクラス名と一緒じゃないといかんのかな?

Python

トランスパイルコマンド: haxe --python main.py --main Main

main.py
# Generated by Haxe 4.2.1+bf9ff69
# coding: utf-8
import sys



class Main:
    __slots__ = ()

    @staticmethod
    def main():
        print("Hello World")


class haxe_iterators_ArrayIterator:
    __slots__ = ("array", "current")

    def __init__(self,array):
        self.current = 0
        self.array = array

    def hasNext(self):
        return (self.current < len(self.array))

    def next(self):
        def _hx_local_3():
            def _hx_local_2():
                _hx_local_0 = self
                _hx_local_1 = _hx_local_0.current
                _hx_local_0.current = (_hx_local_1 + 1)
                return _hx_local_1
            return python_internal_ArrayImpl._get(self.array, _hx_local_2())
        return _hx_local_3()



class python_internal_ArrayImpl:
    __slots__ = ()

    @staticmethod
    def _get(x,idx):
        if ((idx > -1) and ((idx < len(x)))):
            return x[idx]
        else:
            return None


class python_internal_MethodClosure:
    __slots__ = ("obj", "func")

    def __init__(self,obj,func):
        self.obj = obj
        self.func = func

    def __call__(self,*args):
        return self.func(self.obj,*args)




Main.main()

でかい。

コード2

Haxe

Main.hx
class Main {
  static public function main():Void {
    trace("Hello World");

    var items = ["a", "b", "c"];
    for (index in 0...items.length) {
        trace('$index : ${items[index]}');
    }
    if (items.length == 3) {
        trace('length is ');
        trace('3');
    } else {
        trace('length is ');
        trace('not 3');
    }
    trace('end');
  }
}

肝心のコードブロックを作ってみた。

Python

トランスパイルコマンド: haxe --python main.py --main Main

main.py
# Generated by Haxe 4.2.1+bf9ff69
# coding: utf-8
import sys



class Main:
    __slots__ = ()

    @staticmethod
    def main():
        print("Hello World")
        items = ["a", "b", "c"]
        _g = 0
        _g1 = len(items)
        while (_g < _g1):
            index = _g
            _g = (_g + 1)
            print(str(((("" + str(index)) + " : ") + HxOverrides.stringOrNull((items[index] if index >= 0 and index < len(items) else None)))))
        if (len(items) == 3):
            print("length is ")
            print("3")
        else:
            print("length is ")
            print("not 3")
        print("end")


class haxe_iterators_ArrayIterator:
    __slots__ = ("array", "current")

    def __init__(self,array):
        self.current = 0
        self.array = array

    def hasNext(self):
        return (self.current < len(self.array))

    def next(self):
        def _hx_local_3():
            def _hx_local_2():
                _hx_local_0 = self
                _hx_local_1 = _hx_local_0.current
                _hx_local_0.current = (_hx_local_1 + 1)
                return _hx_local_1
            return python_internal_ArrayImpl._get(self.array, _hx_local_2())
        return _hx_local_3()



class python_internal_ArrayImpl:
    __slots__ = ()

    @staticmethod
    def _get(x,idx):
        if ((idx > -1) and ((idx < len(x)))):
            return x[idx]
        else:
            return None


class HxOverrides:
    __slots__ = ()

    @staticmethod
    def stringOrNull(s):
        if (s is None):
            return "null"
        else:
            return s


class python_internal_MethodClosure:
    __slots__ = ("obj", "func")

    def __init__(self,obj,func):
        self.obj = obj
        self.func = func

    def __call__(self,*args):
        return self.func(self.obj,*args)




Main.main()

for じゃない!…のは index in ... でイテレートしてるからかな?まぁコードブロックはよしなにしてくれるのでありがたい。

あと HxOverrides というのが増えてる。

気づき

  • 互換性のためのイテレータコードとか入ってるけど、ロジックでは使ってない。そこは Tree-shaking されないっぽい。でもまぁイテレータなんて実際のコード書いたら100%出てくるから無駄ではないか。
  • python の package manager (pyenv とか poetry とか) で Haxe を Virtualenv スコープにできたら、つよいと思う。

他の気になるポイント

  • python の 3rd party library の使い方
  • IDE補完力(上記ありきだと思うけど)