Haxe覚書き

実に1年と9カ月ぶりのエントリ、私は元気です。
ここでは自分用メモの為にもHaxeを触ってみて、この言語独特だと思うところを書いていきます。

Haxeについての解説は省略

Haxeの型

基本型 - Haxe

Haxeでは、整数値IntはFloatを継承して定義されてます。
Windows用にbuildされたC++のソースを見てみると、Intはint、Floatはfloat or doubleのプリミティブ型でした
※Floatの定義はhxcpp.h


・上記から、数値を扱うGenericな関数を用意する時にはFloatを基底の型として定義します。

function add<T:Float> (lhs:T, rhs:T):T { return lhs + rhs; }

{
  var a:Int = 2;
  var b:Int = 3;
  var c:Int = add(a, b); // 5(Int)
} {
  var a:Int = 2;
  var b:Int = 3;
  var c:Float = add(a, b); // 5(Float)
} {
  var a:Float = 2.1;
  var b:Float = 3.1;
  var c:Int = add(a, b); // compile error.(期待通り)
}


・合計値を算出するsum関数を作る時等は、C#みたいにdefaultキーワードが無いので、少し工夫が必要です。

function sum<T:Float> sum(iterable:Iterable<T>):T {
  var it = iterable.iterator();
  var ret = it.next();
  while (it.hasNext()) ret += it.next();
  return ret;
}

{
  var a:Int = sum([1, 2, 3]); // 6(Int)
} {
  var a:Float = sum([1, 2, 3]); // 6(Float)
} {
  var a:Int = sum([1.1, 2.2, 3.3]); // compile error.(期待通り)
}

試してみたら空配列もいけたのでたぶんこれでOKだと思います。


別解として、戻り値をFloatにするのも手かもしれませんが、個人的にはあまりお勧め出来ないと感じました

function sum<T:Float> sum(iterable:Iterable<T>):Float {
  var ret = 0.0;
  for (x in iterable) ret += x;
  return ret;
}

{
  var a:Int = sum([1, 2, 3]); // compile error.(ダウンキャストが必要)
} {
  var a:Int = cast(sum([1, 2, 3]), Int); // 6
} {
  var a:Int = cast(sum([1.2345, 2, 3]), Int); // run-time error.(一つFloatが紛れてしまってるが、コンパイルは成功してしまい、キャスト時に初めて実行時エラーが出る)
}

sum関数の中身は綺麗に書けるんですが、常にFloatで帰ってくる為、その後にダウンキャストが必要になってしまいます
(ローカルスコープ内でのみ使うのなら、Floatで受け取ってそのまま使ってもあまり問題にならないかもしれませんが)。

LINQライク

Lambdaと、足りない関数を用意すれば、名前は違えどLINQと同じ使い方が出来るとおもいます。

class LambdaExtensions {
  /// @note C# LINQで言うところのSelect
  public static function convert < T, U > (iterable:Iterable<T>, converter:T -> U):Iterable<U> {
    var ret = new Array<U>();
    for (x in iterable) ret.push(converter(x));
    return ret;
  }
  /// @note filterとconvertを別々に実行すると毎回配列が作られてしまう為纏めた
  public static function filterConvert< T, U > (iterable:Iterable<T>, filter:T -> Bool, converter:T -> U):Iterable<U> {
    var v = new Array<U>();
    for (x in iterable) if (filter(x)) v.push(converter(x));
    return v;
  }
}

{
  // [4, 8]
  var ary = [1, 2, 3, 4, 5]
    .filterConvert(
      function(x) { return x % 2 == 0; },
      function(x) { return x * 2; }
    );
}

usingすれば拡張メソッドとして使えるので、名前は違えど使用感はLINQと同じ。


一応hxLINQというライブラリがありますが、
どうやらhaxelibから外れたらしく(haxelib install hxLINQしてもNo such Project : hxLINQと言われる)、
インストールするには、自身でgithubから持ってくる必要があります、
また、hxLINQのselectは中でnullを取り除いていたり、sumの戻り値がFloatになっていたり、関数を呼ぶ度に新しく配列を作り直しているため、
C#LINQと同じ使い方をしていると変にはまったり、乱用するとパフォーマンスに影響が出たりするかもしれません。


とりあえずこんな所です。