himorogiの日記

主にプログラミングに関することなど。少々ハード(電子工作)についても。

Calling overloaded methods

引数の型に基づき、呼び出すメソッドを決定するプロセスをオーバーロード解決と言う。 Javaでは、オーバーロード解決をコンパイル時に行うが、Rhino ではランタイム実行中に行う。動的な JavaScript では変数の型は実行時まで判らないので、オーバーロード解決は実行中にしかできない。

例より、多くの overload メソッドを定義して、それらと呼ぶ以下のJavaのクラスを考える。

public class Overload {

    public String f(Object o) { return "f(Object)"; }
    public String f(String s) { return "f(String)"; }
    public String f(int i)    { return "f(int)"; }

    public String g(String s, int i) { return "g(String,int)"; }
    public String g(int i, String s) { return "g(int,String)"; }

    public static void main(String[] args) {
        Overload o = new Overload();
        Object[] a = new Object[] { new Integer(3), "hi", Overload.class };
        for (int i = 0; i != a.length; ++i)
            System.out.println(o.f(a[i]));
    }
}

このプログラムをコンパイルして、実行すると、以下の出力を得る。

f(Object)
f(Object)
f(Object)

同様のスクリプトを書く。

var o = new Packages.Overload();
var a = [ 3, "hi", Packages.Overload ];
for (var i = 0; i != a.length; ++i)
    print(o.f(a[i]));

これを実行すれば出力を得る。

f(int)
f(String)
f(Object)

Rhino ではランタイム実行時にオーバーロードされたメソッドを決定するので、その際、引数に適合した型を call する。一方 Java ではコンパイル時に引数の型からオーバーロードされたメソッドを選択する。

これには、各々の呼び出しにより適したメソッドを選択できる利点があるが、一方それら呼び出しのときに処理が集中するので性能に影響を与える。 実際には、このオーバーヘッドは軽微である。

オーバーロード解決をランタイムで行うため、ラインタイム実行時にオーバーロード解決に失敗することもある。 例えば、2つの整数を引数に overload のメソッドを g として呼ぶと、メソッドのどちらのフォームも何れの引数の型に適合できずに、error となる

js> o.g(3,4)
js:"<stdin>", line 2: The choice of Java method Overload.g
matching JavaScript argument types (number,number) is ambiguous;
candidate methods are: 
class java.lang.String g(java.lang.String,int)
class java.lang.String g(int,java.lang.String)

http://www.mozilla.org/js/liveconnect/lc3_method_overloading.html で overload 意味論の、より正確な定義を見ることができる。