世代別ガベージコレクションの詳細について

前回までは、Objective-C 2.0のガベージコレクションの機能を解説してきた。その流れに従えば、今回は世代別ガベージコクレションの説明になる予定だった。

しかし、Objective-C 2.0の世代別ガベージコレクションに関するAppleからの情報はとても少ない。ドキュメントから読み取れるものをまとめてみよう。たしかにObjective-C 2.0では、世代別ガベージコレクションを実装している。Incrementalなコレクションも兼ねているようだ。旧世代から新世代への参照を検知するために、ランタイムAPIを使ってライトバリアを実装している。そして、世代は複数に及ぶことができ、2から8の世代をサポートするようだ。(参考: Garbage Collection Programming Guide)

なかなかに興味深い内容だ。コピーGCを行わないランタイムで世代別GCをうまく機能させることはできるのか、8世代にも及ぶ世代分けはどの程度の効果があるのか、など知りたいことはたくさんある。だが、実装の詳細が記述されていないし、ソースコードも公開されていないため、これ以上の内訳を知ることは難しい。

このような理由により、本連載でのガベージコレクション機能の追求は、ひとまず完了したいと思う。今後、詳細な情報が手に入るようであれば、再び検討をしてみたくはあるが。

プロパティ以前のアクセス制御

さて、新しい話題にとりかかろう。取り上げるのはプロパティだ。これは、オブジェクトが持つインスタンス変数へのアクセスに関する実装を簡略化してくれるものだ。

プロパティの前に、Objective-C 1.0までのインスタンス変数へのアクセスについておさらいしよう。インスタンス変数への直接的なアクセスを隠蔽することは、オブジェクト指向では基本とされる。内部情報を隠蔽してカプセル化を推し進め、再利用性の高いコードを書くことができると言われている。

だが、C言語的な自由さをプログラマに与えるObjective-Cでは、やはりその辺りも自由だった。いちおう、インスタンス変数に、@public、@protected、@privateといった、アクセス修飾子を付加することはできる。だが仮に@protectedや@privateを付けたとしても、コンパイル時に警告が出るだけでビルドは通るし実行もできてしまう。これがObjective-Cらしさであろう…と肯定的に捉えるのもさすがに無理がある。これだったら、はじめからないほうがすっきりするだろう。

@interface MyObject : NSObject
{
@private
    // privateなインスタンス変数を宣言する
    int var;
}
@end

int main(int argc, const char* argv[])
{
    MyObject* object;
    object = [[MyObject alloc] init];

    // 警告は出るがビルドは通る
    object->var = 100;

    // インスタンス変数に正しく値は代入されている
    NSLog(@"var is %d", object->var);

    return 0;
}

さらに凶悪なものとして、@defsというコンパイラ指示子もあった。これを使うと、クラスをC言語の構造体のようにアクセスできてしまう。もはやオブジェクトであっても、C言語的な変数の集合体としかみなさなれていないようだ。これはさすがに、Objective-C 2.0ではdeprecatedになったようである。

// MyObjectクラスに、構造体としてアクセス出来るようにする
struct my_object {
@defs(MyObject)
};

int main(int argc, const char* argv[])
{
    MyObject* object;
    object = [[MyObject alloc] init];

    // my_object構造体にキャストして使用する
    ((struct my_object*)object)->var = 100;
    NSLog(@"var is %d", ((struct my_object*)object)->var);

    return 0;
}

このようにObjective-Cでは、インスタンス変数にアクセスしようと思えば、いかような手段を使ってでもアクセスできてしまう。逆にアクセスを禁止することはほぼ不可能ではないかと思えてしまう。

では、これらの機能を積極的に使ってプログラミングするかというと、そんなことはないようだ。経験を積んだプログラマならば、カプセル化を高めるためにアクセッサメソッドを使うところと、スピードを稼ぐために直接インスタンス変数にアクセスするところを、切り分けて区別することができるだろう。どちらの手段を採用するかは、プログラマの裁量しだいだ。

Objective-Cの言語仕様を見ていると"自由と責任"という言葉が頭に浮かぶ。言語的に何かを禁止するということは、Objective-Cではあまりない。むしろ、積極的に内部構造にアクセスするための文法やAPIを提供してくれている。あとは、それらを使うプログラマの責任なのだ。大いなる自由と引き換えに、秩序あるプログラムを作る責任も押し付けられるのだ。

話が大きく脱線してしまったが、こんな状況で現れたのがプロパティだ。次回からこのプロパティを詳しく取り上げよう。