Haxeについて
小泉 守義 <mozo@mozo.jp>
自己紹介
「日本の●●ユーザのためのハブサイト」ブーム時
にhaxe-users.jpをひっそりと立ち上げたりした
名古屋界隈はOCaml Meeting 2013で忙しいよう
なので...
すいませんすいません
http://www.mozo.jp/
HAXE
読み方、
分かりますか?
Haxeとは
発音は hex (ヘックス)
ActionScript3 / ECMAScript 4 によく似た文法
マルチターゲットなコンパイラ (JS, C++, PHP...)
最適化 (インライン化、定数畳み込み、DCE等)
静的型付けと型推論、匿名型 (動的型サポートあり)
代数型データ型とパターンマッチ
リフレクション
強力なマクロ
ビルトインのパッケージングシステム (haxelib)
OCamlで書かれている
Haxeの歴史
2004年 MTASC (AS 2.0のコンパイラ)
Nicolas Cannasse 作
2006年 Haxe1.0
2008年 Haxe2.0
PHP / C++ターゲット、マクロ
2013年 Haxe3.0
C# / Javaターゲット、配列内包表記、abstract
Haxeでの作業フロー
エディタでコードを書く
class Main {
public static function main():Void {
js.Lib.alert("Hello, world!");
}
}
Haxeでの作業フロー
コンパイルする
main.js が生成される
$ haxe -main Main -cp . -js main.js
Haxeでの作業フロー
生成されたコード (抜粋)
$estr = function() { return js.Boot.__string_rec(this,''); }
Std = function() { }
Std.__name__ = ["Std"];
Std["is"] = function(v,t) {
return js.Boot.__instanceof(v,t);
}
...
js.Lib.alert = function(v) {
alert(js.Boot.__string_rec(v,""));
}
...
Main = function() { }
Main.__name__ = ["Main"];
Main.main = function() {
js.Lib.alert("Hello world");
}
HAXE
Haxeの言語構造 基本
基本的な構文は *あの* ECMAScript 4とほぼ同じ
変数定義 (var) / 定数定義 (const)
演算子
if ... else
for(in) / while
構造化例外 try { } catch (...) { }
パッケージ
Haxeの言語構造 基本
var i:Int = 1 + 2; // 型名は後置
var r = 3.4; // 型は推論される
trace(y); // yは定義されていないの
でコンパイルエラー
Haxeの言語構造 型
型名は必ず大文字で始まる
enum 型、class 型、interface 型、関数型、
匿名型、Dynamic, abstract
ビルトイン型: Void, Float, Int, Bool, Dynamic,
String, Null<>
Haxeの言語構造 class型
他のクラスを「extends」でき、インターフェイス
を「implements」できる
メンバ変数、プロパティ、メソッド、任意でコンス
トラクタを持つ
Haxeの言語構造 class型
class Foo {
// このクラスの外部からアクセスできる
public var a:Int;
// このクラスとそのサブクラスから
// アクセスできる (他言語のprotected相当)
private var b:String;
var c:Float; // private と同じ
static var d:Int; // 静的変数
}
Haxeの言語構造 class型
class Foo {
function foo():Void { }
// 引数と任意引数
function faa(a:Int, ?b:Int):Int {
if (b == null) {
return a;
} else {
return a + b;
}
}
}
Haxeの言語構造 class型
class Foo {
// 静的メソッド
static function bar() { }
// コンストラクタ
public function new() { }
// クラスイニシャライザ
static function __init__() { }
}
Haxeの言語構造 class型
class Foo {
public var a(get, set):Int;
public var b(get, null):Int;
var c(get, never):Int;
function get_a():Int { ... }
function set_a(v:Int) { ... }
function get_b():Int { ... }
function get_c():Int { ... }
}
Haxeの言語構造 interface型
プロパティ、メソッドの宣言ができる
interface Foo {
var prop(get, set):Int;
function foo(a:Int, ?b:Int):Int;
}
Haxeの言語構造 関数型
アロー (->) を使って定義
複数引数がある場合はアローを複数個書く
var lmb:Int->Int =
function(x:Int):Int { return x * 2; };
// この場合関数の引数および戻り値の型は推論される
lmb = function(x) { return x * 2; };
// Int に対する Float の加算は未定義なのでエラー
lmb = function(x) { return x + 1.0; };
var luminance:Int->Int->Int->Float =
function(r, g, b) { ... };
Haxeの言語構造 enum型
CやC++の enum と違い、個々のメンバはコンスト
ラクタを持ち、パターンマッチが可能。
パターンマッチは switch 文を用いて行う
パターンマッチと同時に destruction も可能
enum Foo {
foo;
bar(a:Int);
baz(a:Int, b:Int);
}
Haxeの言語構造 enum型
var f:Foo = bar(2);
switch (f) {
case foo:
trace("foo");
case bar(a):
trace("bar: ", a);
case baz(a, b):
trace("baz: ", a, b);
}
Haxeの言語構造 enum型
enum Foo {
foo;
bar(a:Int);
baz(a:Int, b:Int);
}
Haxeの言語構造 匿名型
匿名型の宣言
型名が現れる場所での宣言
匿名型の継承
typedef Point = { x:Float, y:Float };
var p:{ x:Int, y:Int };
var q = { x:10, y:10 };//メンバ型は推論される
p.x = 20; // OK
q.x = 20.0; // 型が違うのでコンパイルエラー
typedef Point3D = { >Point, z:Float };
Haxeの言語構造 匿名型
構造的サブタイピング
var x:{ x:Float, y:Float };
var y:{ x:Float, y:Float, z:Float };
x = y; // OK
Haxeの言語構造 Dynamic
すべてのクラスで暗黙に実装するインターフェイス
型と見なされる
var x:Dynamic = 1;
x = ""; // 型は違うが代入OK
Haxeの言語構造 Dynamic
Dynamic型に対する操作では、あらゆる型検査がバ
イパスされる
ターゲット言語の型システムの挙動に依存するの
で、ターゲットによって挙動が変わることに注意
var x:Dynamic = 1;
x += ""; // コンパイルは通るが、ランタイムエラー
になる可能性
var y:Int = x; // 勝手にアップキャストされる :(
trace(y + 4); // ランタイムエラーになる可能性
Haxeの言語構造 Dynamic
フィールド型の限定
var x:Dynamic<Int> = {};
x.a = 1; // OK
x.b = 1.0; // コンパイル時エラー
Haxeの言語構造 abstract
abstractキーワードで定義
暗黙のキャストの定義、および演算子のオーバロー
ドを可能にする
Scalaのimplicit conversion、Goの型宣言と似た
ようなセマンティクスを持つ
Haxeの言語構造 abstract
型の拡張
@:coreType abstract ErrorCode from Int {}
@:coreType abstract ErrorCodeEx from Int
to Int {}
...
var a:ErrorCode = 1; // OK
var b:Int = a; // コンパイルエラー
var c:ErrorCodeEx;
var d:Int = c; // OK (to castが宣言されてい
る)
a = c; // OK
c = a; // NG
Haxeの言語構造 abstract
Opaque types
abstract StringExtension(String)
from String to String {
public function pluralize() {
return this + "s";
}
}
...
var s:StringExtension = "language";
trace(s.pluralize()); // "languages"
Haxeの言語構造 abstract
演算子のオーバーロード
typedef Point = { x:Float, y:Float };
abstract Vector(Point) from Point to Point {
@:op(A + B)
public static function add(lhs:Vector, rhs:Point): Vector {
var _lhs:Point = lhs;
return { x:_lhs.x + rhs.x, y: _lhs.y + rhs.y };
}
@:op(A * B)
public static function product(lhs:Vector, rhs:Point):
Float {
var _lhs:Point = lhs;
return _lhs.x * rhs.x + _lhs.y * rhs.y;
}
}
Haxeの言語構造 abstract
演算子のオーバーロード (続き)
var p:Vector = { x: 1., y: 1. };
p += { x: 2., y: 3. };
var tmp:Point = p;
trace(tmp.x, tmp.y); // yields 3., 4.
trace(s * { x: 1., y: 2. }); // yields 11.
Haxeの言語構造 型パラメータ
いわゆるジェネリクス (type erasure)
共変性と反変性の「部分的な」サポート
Haxeの言語構造 型パラメータ
class Base {}
class Extended extends Base {}
class GenericStuff<T:Base> {
public function new() {}
}
...
// コンパイルエラー (covariance)
var x:GenericStuff<Base> =
new GenericStuff<Extended>();
// ターゲット言語によってはコンパイルエラー
var x:Int = null;
// OK
var y:Null<Int> = null;
Haxeの言語構造 nullable
値型 (基本型) にはnullが代入できない
nullを代入可能にするには Null<> を用いる
Haxeの言語構造 マクロ
HaxeのマクロはHaxeで記述する
ASTを注入できる、ゆえになんでもできる
.NET の式ツリー (expression trees) に似ている
マクロを地の文と同じ場所に書く都合から、同じソ
ースが2回解釈されることに留意 (macroコードと非
マクロコードのそれぞれのコンパイルのため)
@:build() / @:autoBuild() ノーテーション
#if !macro ... #end ガード
Haxeの言語構造 マクロ
macro キーワードclass Foo {
macro public static
function makeVar():haxe.macro.Expr {
// macro を付けると、以降の expression のコンパイル結果が
// ASTとして評価される。.NETの式ツリーのラムダ式に似ている。
return macro var b = 2;
}
}
Haxeの言語構造 マクロ
macro キーワード
class Foo {
// makeVar を書き下したもの
macro public static function makeVar2():haxe.macro.Expr {
return {
expr: EVars([
{
type: TPath({ sub:null, name:"Int", pack:
[], params:[] }),
name: "b",
expr: {
expr: EConst(CInt("2")),
pos: haxe.macro.Context.currentPos()
}
}
]),
pos: haxe.macro.Context.currentPos()
};
}
}
Haxeの言語構造 マクロ
#if !macro
public function foo() {
makeVar(); //マクロの呼び出し
trace(b); //bが定義されている!
}
#end
Haxeの言語構造 内包表記
var a = [for(x in 0...5) x];
trace(a); // [0, 1, 2, 3, 4]
Haxeの言語構造 その他
cast
untyped キーワード
using (.NET の拡張メソッドと似ている)
Map (String以外のキーをサポート)
var a:Int = cast(1.2, Int);
untyped {
var a = 1;
a = a + ”B”;
}
Haxe as a generator
externキーワード
__js__ キーワード
js.* パッケージ
extern
ターゲット言語で定義されるクラスをHaxe内で利用
するための機能
extern class Element extends Node {
public function
getAttribute(name:String):String;
...
}
__js__
生成されるコード中にターゲット言語 (JavaScript)
の記述を直接インジェクションする
untyped キーワードと共に利用
untyped __js__(“<E4X></E4X>“);
js.*パッケージ
HTML DOMやよく使われるライブラリ (jQuery) な
どのバインディングを提供
import js.Browser;
import js.JQuery;
...
Browser.window.console.log(”hey”);
var n = jQuery(domElement).find(”.inner”);
まとめ
Haxeは様々な言語の要素を集約した、痒いところに
手が届く、マルチパラダイムな言語
しかも7年の歴史がある
JSのジェネレータとしてだけでなく、普段使いした
くなる!

Haxeについて