haXe と JSX の最大の違いは null と undefined の扱い

JavaScript のコードをデバッグ中、突然出現する null や undefined に苦しめられている方も多いのではないでしょうか。haXeJSX の一番大きな差は、個人的には、その null (と undefined) の扱いにあると考えています。

haXeJavaScript 実装では、全ての基本型が nullable とされています*1。つまり、たとえば haXe の Bool 型は true, false, null の3つの値を取りうることになります*2。null が入っているかどうかはプログラマがいちいち確認する必要があります。

// haXe
class Test {
  static function f(b : Bool) : Void {
    if (b == true) {
      // b is true
    } else if (b == false) {
      // b is false
    } else {
      // b is null
    }
  }
}

一方、JSX は JavaScript の仕様に則り、基本型は nullable ではありません。boolean 型は true か false かのいずれかの値を取ります。

// JSX
class Test {
  static function f(b : boolean) : void {
    if (b) {
      // b is true
    } else {
      // b is false
    }
  }
}

なぜ、haXe は、このような仕様になっているのでしょう。それは、以下のコードを見ればわかりやすいと思います。

// haXe
class Test {
  static function f(b : Bool) : Void {
    if (b == true) {
      // b is true
    } else if (b == false) {
      // b is false
    } else {
      // b is null
    }
  }
  static function g() : Void {
    Test.f((new Array<Bool>(1))[0]);
  }
}

JavaScript の配列要素のデフォルト値は undefined*3 です。したがって、上のようなコードをオーバーヘッドを小さい形で実行可能とするためには、全ての基本型に null (== undefined) を許容せざるを得ない。そのように考えた結果なのでしょう。

では、JSX の boolean 型はなぜ non-nullable なのか? 以下のコードを jsx でコンパイルして Google Chrome で開いてみると、undefined を boolean として扱おうとした瞬間にデバッガが起動して、JSX のソースコードが表示されるのがわかると思います。

// JSX
class Test {
  static function f(b : boolean) : void {
    if (b) {
      // b is true
    } else {
      // b is false
    }
  }
  static function g() : Void {
    Test.f(new Array.<boolean>(1)[0]); // ← この行でデバッガが起動する
  }
}

JSXでは、このように null (== undefined) へのアクセスを積極的にエラーとして扱い、デバッガと連携することで、プログラムの品質を高めようというアプローチを取っているわけです。ちなみに、このデバッガ起動用のコードは --release オプションをつけて最適化つきでコンパイルした場合は、出力されません。

個人的には、この違いが一番大きいところなのではないか、と思っています。

*1:参照: http://haxe.org/manual/basic_types#nullability

*2:これは正確に言うと、haXeJavaScript へのコンパイラにおいてそういう仕様になっているのであって、C++ 等に変換する場合は基本型は non-nullable として扱われるそうです

*3:== 演算子で比較した場合 null と同値