ActionScript3.0やC#などと異なる挙動なので、ちょっと見落としがちなHaxeのoverrideの挙動についての話です。
戻り値はより狭い型を指定しても良い
Haxeでは以下のように、関数の戻り値に元の型より狭い型を指定してもエラーになりません。
class A{
public static function main() {}
public function a():Float {
return 0.5;
}
}
class B extends A {
public override function a():Int {
return 1;
}
}
見慣れないとこれがコンパイルエラーにならないのは問題がありそうにみえますが、深く考えてみれば問題がないことがわかります。
あるAのインスタンスについての関数aの呼び出しを考えてみます。
var number:Float = a.a();
この関数の返り値はFloatです。そして、HaxeではIntはFloatに含まれる型なので返り値がIntでも問題無いわけです。
何の矛盾も生じないのですからコンパイルエラーにする必要がありません。
このように戻り値の型を元の型よりも限定された型に変えるのを共変戻り値型と言います。
では、逆の場合はどうでしょう?
class A {
public static function main() {}
public function a():Int {
return 1;
}
}
class B extends A {
public override function a():Float {
return 0.5;
}
}
逆はコンパイルエラーになります。FloatにIntを代入することはできません。
引数はより広い型を指定しても良い
関数の引数に元の型より広い型を指定してもエラーになりません。
class A {
public static function main() {}
public function a(number:Int) {}
}
class B extends A {
public override function a(number:Float) {}
}
考え方は戻り値の時と同じです。
a.a(1);
上記のような呼び出しでは、関数aの引数の受け取り側がFloatであったとしても矛盾は生じないのでエラーになりません。
このように引数の型を元の型よりも抽象的な型に変えるのを反変引数型と言います。
もちろん逆に、引数をより限定的な型に変えようとするとエラーになります。
privateをpublicでoverrideしても良い
上記の2つと同じで、矛盾は生じないのでコンパイルエラーになりません。
class A {
public static function main() {}
private function a() {}
}
class B extends A {
public override function a() {}
}
逆にpublicをprivateでoverrideすることはできません。
以上、Haxeは矛盾しない範囲でなら寛容なoverrideができて、ちょっとうれしいよという話でした。