5月2010

最近ちょくちょくサーバーが落ちてます

自宅サーバーを立てて、早くも一年が過ぎました。夏に物理的な故障で落ちた時以外、あまりサーバーが落ちたことはなかったのですが、最近月に一回くらいのペースで落ちています。

前回落ちたときは、ログに crash という文字があったので、何かあったんだという事はわかりましたが、昨日から今日にかけて落ちていたのは、特にログを見ても何も残っていなかったので、原因が不明です。ログを探すのが甘いのかもしれませんが、今の私のスキルだと、この程度です。

来月も1回落ちるようでしたら、おそらくソフトウェアの障害だと思われるので、週1で再起動させるようにして、様子を見てみることにしてみます。

なぜ Objective-C は気持ち悪いのか – 完

なぜ Objective-C は気持ち悪いのか分析してみる企画。これまで、見た目やクラスについての気持ち悪さを考えましたが、最後に全体的に気持ち悪くしている要素を探ろうと思います。

参照カウンタ方式

Objective-C をはじめて最初に躓くのが、このメモリ管理だと思います。わかってしまえば、非常に簡単なルールで管理されていることが理解できるのですが、理解するのが少し難しく感じる方も多いようです。また、Javaの人から見ればガベージコレクションないの?C++の人から見れば、スマートポインタないの?なぜいまどき、煩わしそうな参照カウンタ方式を採用しているのだろうか、と思われることでしょう。しかし、実際には、それほど煩わしいものでもなく、ガベージコレクションよりはパフォーマンスはいいので、デメリットしかないわけではありません。2.0からは、ガベージコレクションを有効にもできます。

nilが無視される

NullPointerException の例外は有名です。Cでは、nullにアクセスするとセグメントエラーになったりします。 Objective-C ではどうでしょうか?なんと、nilにメッセージを送信しても、エラーにならないどころか、無視される仕様になっています。例えば、こんなコードを書きます。

NSString *s = nil;
NSLog( @"%@", [s description] );

何もなかったかのように、普通に実行されて終わります。実は、Objective-C では、nilにメッセージを送信したときの動作が決まっており、メソッドの戻り値が false の値をとるように実行されます。戻り値の型がidならnilで、戻り値の型がintなら0といったようにです。これは非常に気持ち悪く感じる方も居られるでしょう。なぜなら、エラーが発見しにくくなるからです。うまく実行できないと思ったら、オブジェクトがnilだったというようなことは、Objective-C においてはたまにあることです。

フレームワークが謎めいた動作をする

Objective-C とあわせて使われる Foundation フレームワークは、かなり不思議な動作をすることがあります。それはアプリケーションをデバッガで追ってみるとすぐにわかるでしょう。なんと、知らないクラス名がたくさん見えます。自分で生成した覚えの無いクラスがたくさんデバッガに写っていることでしょう。しかも、そのオブジェクトが、明らかに自分の生成したオブジェクトであったりすると、かなり気味の悪いことです。そう、Objective-C では表面上はドキュメント通りの動作をしているけれども、中を見てみると想像もできないような動きをしていることがあるのです。

NSString *s = [[NSString alloc] initWithFormat:@"string"];
NSDate *d = [[NSDate alloc] init];
NSNumber *n1 = [[NSNumber alloc] initWithInt:10];
NSNumber *n2 = [[NSNumber alloc] initWithInt:10];

例えば、これらのインスタンスの本当のクラス名は、実際とは異なります。これくらいなら、ドキュメントにも書かれているのですが、もっと複雑なプログラムを組んでいると、いつの間にか変なクラスを操作していることがあります。また、興味深い点としては、n1とn2は全く同じインスタンスを指す点です。NSNumberは、同じ値の場合、同じインスタンスを返すような動作をします。不思議ですね。alloc,initメソッドの定義は、面倒なだけではなく、このような動作をさせたいときに使えるのです。必ずしも、自分が期待する動作をしているわけではないことに注意すべきです。表面上は、そのようになっているということが、Objective-Cにおいては多々あります。

まとめ

ぱっとあげてみると、これくらいのことが思いつきました。この他にもまだまだ、 Objective-C が気持ち悪く感じる点はあるかと思います。

これまでの3回の記事で、Objective-Cが気持ち悪い理由を考えていましたが、正確に言えば、気持ち悪く思われそうな理由を考えていました。なぜなら、私はひとつも Objective-C を気持ち悪いだなんて思っていないからです。メッセージ式ひとつをとっても、オブジェクト指向のメッセージングを適切に表現した形に見えす。

私が Objective-C に惹かれたのは、その素直なオブジェクト指向の実現の仕方にあります。 Objective-C のオブジェクト指向は、純粋にオブジェクト同士の対話であり、すべて動的に行われます。私が Objective-C で最も気に入ってる点は、その書き味の良さです。思ったとおりのコードを、すばやく書くことができます。それは、 Objective-C の動的なものからくるゆるさというものも、少なからず影響していると思います。

過去2回のリンク

ガベージコレクションのアルゴリズムと実装

巷でGC本と噂されるこの本。思わず買ってしまいました。

ガベージコレクションのアルゴリズムと実装 ガベージコレクションのアルゴリズムと実装
竹内 郁雄

秀和システム 2010-03-18
売り上げランキング : 2404

Amazonで詳しく見る by G-Tools

ガベージコレクションに興味のある方は、もはやこの本を読む以外の選択肢はないと言っても言い過ぎではないでしょう。なぜなら、ガベージコレクションのアルゴリズムがこれほど載せられた本や資料は、ほとんどないからです。ガベージコレクションに興味を持ったら、まずこの本を読んで、それから実際のコードを見に行くと、より早く理解が進められることと思います。

なぜ Objective-C は気持ち悪いのか – クラス編

なぜ Objective-C は気持ち悪いのか分析してみる企画。前回はコードの見た目について考えましたが、今回はクラスについて考えてみます。

クラス

動的な生成のみ

Objective-C は、静的なインスタンスを生成することはできず、必ず動的なインスタンスを生成しなければなりません。常にポインタで扱うことになるので、高速な反面、メモリ管理の煩わしさが常につきまといます。通常、インスタンスの生成、破棄は次のようにします。

id object = [[NSObject alloc] init];
[object release];

NSObject に対して alloc メッセージを送り、インスタンスのメモリ領域を生成します。そのあとに、それに init メッセージを適用し、インスタンスを初期化します。ほとんどの場合、alloc, init はペアにして実行します。なぜなら、alloc しても init しなければインスタンスは使用できないからです。この一見奇妙なインスタンスの生成も、 Objective-C の気持ち悪さを助長していることでしょう。

メソッド宣言

前回の記事であった通り、 Objective-C のメソッドでは引数にラベルをつけます。したがって、メソッドの宣言も他の言語とは大きくことなっています。例えば、rangeOfStringのメソッド宣言は、次のようになっています。

- (NSRange)rangeOfString:(NSString *)aString
- (NSRange)rangeOfString:(NSString *)aString options:(NSStringCompareOptions)mask
- (NSRange)rangeOfString:(NSString *)aString options:(NSStringCompareOptions)mask range:(NSRange)aRange
- (NSRange)rangeOfString:(NSString *)aString options:(NSStringCompareOptions)mask range:(NSRange)searchRange locale:(NSLocale *)locale

読み方を説明します。先頭の “-” は、インスタンスメソッドの意味です。”+” にすると、クラスメソッドの宣言となります。次の “(NSRange)” は、戻り値の型です。次の “rangeOfString” がメソッド名です。引数を取る場合は、 “:” で区切って引数を指定していきます。 第一引数にはラベルが必要ないので、メソッド名に続けて “:” を書き、そのあとに “(型名)引数名”となります。第二引数以降は、”ラベル:(型名)引数名” と宣言します。各引数は、スペースで区切ります。

簡単な説明かつ説明下手なところもありますが、若干ややこしく見慣れない記述に、はじめての方は気持ちの悪さを感じることがあるかもしれません。

コンストラクタ, デストラクタの定義

オブジェクト指向プログラミング言語で当たり前な機能に、コンストラクタとデストラクタがありますが、実は Objective-C において、コンストラクタ, デストラクタの機能はありません。しかしながら、それとほぼ同等の機能が用意されています。次のコードは、クラスのメソッド定義です。

- (id)init
{
	self = [super init];
	if ( self ) {
		// ここに初期化コードを書く
	}
	return self;
}

- (void)dealloc
{
	// ここに終了コードを書く
	[super dealloc];
}

問題なのは、Objective-C におけるコンストラクタ, デストラクタは全手動でメソッドを記述する点です。例えば、コンストラクタにあたる init メソッドは、上のコードのように記述する決まりとなっています。デストラクタも同様です。最初の項目で説明した、動的なクラス生成のときにもありましたが、alloc でインスタンスを生成した後に、init メソッドを呼び出すのはこのためです。

ちなみに、init メソッドについては、通常上のような記述で初期化をしますが、シングルトンインスタンスなどを作成する場合には、上とは異なった記述をすることもあります。自分で init を定義する労力がある分、それ相応の自由度はあるというわけです。

以上、クラス編はこんな感じです。次は、フレームワークも含めた全体的な印象の話をしようと思います。