読者です 読者をやめる 読者になる 読者になる

M12i.

学術書・マンガ・アニメ・映画の消費活動とプログラミングについて

JavaプログラマーからみたVala (4) クラス②

Vala Java

原典は、“Vala for Java Programmers”(2011年3月13日取得)です。

******************************

列挙型

Javaの場合: 列挙型はクラスをベースにしています。

Valaの場合: 列挙型は整数をベースにしています。メソッドは持てますが、コンストラクターやフィールドなどは持つことができません。

enum Season {
    SPRING,
    SUMMER,
    AUTUMN,
    WINTER;

    public bool is_hot () {
        return this == SUMMER;
    }
}

実行時の型判別

動的型チェック

Javaの場合: instanceof演算子を使用します。

Valaの場合: is演算子を使用します。

動的型キャスト

Javaの場合:

Foo foo = (obj instanceof Foo) ? (Foo) obj : null

Valaの場合:

Foo foo = obj as Foo

もちろん、 "(obj is Foo) ? (Foo) obj : null"も同様に有効な式です。

型情報を取得する

Javaの場合:

Class c = Foo.class;
System.out.println(c.getName());
Foo = (Foo) c.newInstance();

Valaの場合: typeof()を使用します。

Type t = typeof (Foo);
stdout.printf ("%s\n", t.name ());
Foo o = (Foo) Object.new (t);

オブジェクトの破棄

Javaの場合: 終了化子(finalizers)は、非決定論的です。

public class Foo {
    @Override
    protected void finalize() {
    }
}

Valaの場合: デストラクタ(destructors)は、決定的です。

public class Foo : Object {
    ~Foo () {
    }
}

アノテーション

Javaの場合: アノテーションは自己定義的です。

Valaの場合: アノテーションの代わりに属性(attributes)を用います。属性はコンパイラに組み込まれています。書式は、“[AttributeName (param1 = value, param2 = value)]”というかたちです。バインディング(bindings)やD-Busインターフェースのためにしばしば使用さてます。バインディングのために使用されるいちばんよく見る属性は、“[CCode (...)]”です。

プロパティ

Javaの場合: Bean規約が用いられます。getX()setX()という形式のメソッドです。

public class Person {
    private int age = 32;
    public int getAge() {
        return this.age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public static void main(String[] args) {
        Person p = new Person();
        p.setAge(p.getAge() + 1);
    }
}

Valaの場合: プロパティ──get {} ・ set {}ブロック──がサポートされており、フィールドのようにアクセスできます。

public class Person : Object {
    private int _age = 32;
    public int age {
        get { return _age; }
        set { _age = value; }
    }
}

void main () {
    var p = new Person ();
    p.age++;
}

標準的な実装であれば、さらに短くできます。

public class Person : Object {
    public int age { get; set; default = 32 }
}

デリゲート、クロージャ

Javaの場合: デリゲート・パターンの実装は、匿名内部クラスを使用することになります。

public interface MyDelegateType {
    public void invoke(int a, double b);
}

public class Demo {
    private static void foo(MyDelegateType deleg) {
        deleg.invoke(32, 0.25);
    }

    public static void main(String[] args) {
        MyDelegateType deleg = new MyDelegateType () {
            public void invoke(int a, double b) {
                System.out.println("a = " + a + "; b = " + b);
            }
        };

        deleg.invoke(42, 0.75);
        foo(deleg);
    }
}

Valaの場合: Vala言語は、デリゲートとクロージャをサポートしています。

delegate void MyDelegateType (int a, double b);

void foo (MyDelegateType deleg) {
    deleg (32, 0.25);     // invoke delegate
}

void main () {
    MyDelegateType deleg = (a, b) => {
        stdout.printf ("a = %d; b = %g\n", a, b);
    };

    deleg (42, 0.75);     // invoke delegate
    foo (deleg);          // pass delegate to a method
}

クロージャは外部スコープ(それ自身が定義されたスコープ)のローカル変数を束縛する無名のメソッドです*1。クロージャはデリゲート型の変数に代入したり、デリゲート型の引数として他のメソッドに渡すことができます。

Java言語においては、匿名内部クラスにより、クロージャのまねごとができます。しかし匿名内部クラスが束縛できる外部スコープ・ローカル変数は、final宣言されたものだけです。一方、Vala言語ではクロージャはいかなる変数でも束縛できます。Java7ではクロージャのサポートが計画されています。メソッドは直接デリゲート変数に代入できます。

delegate int MyDelegateType (int a, double b);

int add (int a, int b) {
    return a + b;
}

int sub (int a, int b) {
    return a - b;
}

void main () {
    MyDelegateType deleg = add;
    int sum = deleg (2, 3);
    deleg = sub;
    int diff = deleg (8, 4);
}

このことが示すのは、メソッドは(訳者:クロージャに限らずこれまで登場してきたあらゆる種類のメソッドは)オブジェクト同様に変数に格納したり引数として渡したりできるということです。

******************************

JavaプログラマーからみたVala (5)につづく──

*1:訳者:JavaScriptの関数がまさにそれです。Java6ではfinal宣言された変数でないと外部スコープの変数にはアクセスできませんが、JavaScriptも含め他の言語の中にはこうした変数の読み書きを行えるものがあります。JavaScriptではこの方法で他のコードがアクセスできない文字通り匿名の名前空間を展開・保持するテクニックが頻繁に使用されます。