Vala Array +=

前回の Vala コードでウッカリしていたことがある。
配列に += しているって何よ…

なんだけど valac は何のエラーも吐かなかった、どういうことだ?
C# では ArrayList か generic を使わないかぎり配列数は固定である。

Python ばかりやっていたので配列の長さは可変だと思い込んでいたわけで。
いや、Python では append() なんだけど、何故か += でイケると思った次第で。
わけがわからないよ。

とにかく何故コンパイルが成功したか確かめる。

前回のコードを -C オプションして C コードを見ると g_renew() で配列を新たに作り直ししている。
C の配列に展開ではなくポインタのポインタに展開するのか、なるほどコレなら動的に増やせる。
つまり Python みたいに可変個数で使えるということなの?
ドキュメントを漁るが見当たらず、自分で実験だ。

ローカル変数で試すと普通にエラー、サンプルコードは必要無いね。
メンバ変数にしているからだろうか。

ところでメンバ変数を参照するコードは main 関数内に書いてはいけないよ。
static 関数からは同じく static 宣言をしたものか定数しか参照できない。
vala は C 言語に展開する言語なのに class の制約はしっかりチェックするのね。

// Error
public class ArrayTest {

    public int[] integer;

    public ArrayTest () {
        integer += 1;
    }
}

public class Main {
    public static int main ( string[] args ) {
        new ArrayTest();
        return 0;
    }
}

駄目ジャン!
どうしてエラーにならなかったのだろう…

まてよ、GtkTextView は GtkWidget で構造体だ。
class や struct の配列ならどうなるのだろう。

// Success

public class TestClass {
    public int x;
    public int y;
    public TestClass (int _x, int _y ) {
        x = _x;
        y = _y;
    }
}

public struct TestStruct {
    int x;
    int y;
}

public class ArrayTest {

    private TestClass[] class_array;
    private TestStruct[] struct_array;

    public ArrayTest () {
        // class +=
        var ca = new TestClass(2, 4);
        var cb = new TestClass(92, 777);
        class_array += ca;
        class_array += cb;
        foreach ( var obj in class_array ) {
            stdout.printf ( "%d,%d\n", obj.x, obj.y );
        }
        // struct +=
        TestStruct sa = { 123, 654 };
        TestStruct sb = { 69, 8888 };
        struct_array += sa;
        struct_array += sb;
        foreach ( var obj in struct_array ) {
            stdout.printf ( "%d,%d\n", obj.x, obj.y );
        }
    }
}

public class Main {
    public static int main ( string[] args ) {
        new ArrayTest();
        return 0;
    }
}

マジかよ、普通に += できてしまった、foreach も使える。
つまり構造体という GLib のオブジェクトもどきの配列ならあの _vala_array_add というコードを作成するということなのか。
C# は配列ではこんなことできないよ。

でも配列の一部を取り除く方法は見つからない、できないっぽい。
-= を試すと「配列に算術演算子は使えないよ」ってエラーが出るが += は使えるジャンとツッコミたくなる、だからウッカリしたんだし。
解ったうえで使えば便利かも。

というか、実用では素直に以下のどちらかを使ったほうがいいと思う。
GLib.Array ? glib-2.0
GLib.List ? glib-2.0