最近のトラックバック

2021年7月
        1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
無料ブログはココログ

« 2008年7月 | トップページ | 2008年9月 »

2008.08.28

typedefと前方参照

Objective-Cのプログラミングで起きた事件で最近印象深かった件。

Objectice-CではC++と同様に前方参照の機能がある。例えば適当なヘッダファイル内のクラス定義で、

@class T;
@interface A : NSObject {
T* _t;
...

みたいにして、Tの定義が出るより前にコンパイルを通すことができる。これを使うと、ファイルのインクルード順はあんまり気にしなくてもよくなるでたいへん便利である。
しかし問題になるのは、この"T"がクラスではなく、後方でtypedefで定義される場合だ。このときは、Tのtypedefが先に来るようにインクルード順をもってくる以外に手段は存在しない。いろいろ試行錯誤したが失敗した。

ただ、typedefの中身に前方参照が含まれているのは問題ない。

@class T;
typedef T S;
@interface A : NSObject {
S* _t;

これならOKである。でも、Sのtypedefが後方でもう一度出現するのは定義の中身が同一であってもNGである。

 さらにやっかいなのは、自分のコードではわりとでかい#defineマクロをグワッと展開するとクラス定義やtypedef一式が生成されるようになっていて、なかなかtypedefだけを先に持ってくることが面倒くさいことだ。こういう事態に備えて、enum系を含むtypedef一式は別ファイルに分離するのがよいのかもしれない。

 そして二重に驚きなのは、この制約はC++でも同じであるにもかかわらず、過去この問題で悩んだ記憶がないということだ。typedefはあまり使っていなかったのかもしれないし、この程度のことを面倒だと思う心を持ち合わせていなかったのかもしれない。C++のtemplateは酷使していた記憶があるので一度くらいこれでひっかかってもいいと思うのであるが...

 ここ数年、C#やJavaなどの2パス型コンパイラの言語しかいじってなかったのでインクルード順に気を配るようなセンスがまったく失われているぜ。
 昔はフルビルドに結構時間がかかるプロジェクトも多かったので、「いろいろなところから#includeされているファイルを修正する」ことに恐怖感があったものだが今はそういうのはないよなあ。
 もうファイルを分割するのが面倒なのが先にきて、必要なのはtypedef一個であるにもかかわらずでかいファイルをまるごと#importして「ま、いいか」となっている。


2008.08.25

ZED観てきました

一昨日の土曜、 ZED を見てきました。

シルク・ドゥ・ソレイユのアメリカ以外で最初の常設公演。

常設ということなので、 KA や O に匹敵する舞台装置があるのではとワクワクしていたけど、さすがにそれには及ばなかった。やっぱりKAのあの舞台の回転・傾斜はぶっ飛んでいるからな...

でもそれは舞台装置の話であって、アクロバティックな動き、衣装、音楽ではこれまでに見た演目の中でもトップレベルと思う。内容的には、ラスベガスのTIで観た Mystere のバージョンアップ版。
Mystereで妻のお気に入りだった、筋肉質の2人が凄いポーズをとるやつもあった。「筋肉がプルプルしとる!」と大喜び。


僕の総合評価では
KA > ZED > O > Alegria 2 > Mystere >>>> Zumanity
かな。

なんにしても、このクオリティのものが電車でひょいと観にいけるようになったというのは実に嬉しい。今後も年1回は行きたいところだが、子供が小さいうちは難しいかもな。

今後行く人のためにアドバイス:

* 劇場が円に近いので、中央付近で観たほうがよい。Cブロックがベストで、端っこのA、Eは避けたい。Webで予約するとき、購入をキャンセルしてやりなおすと別の座席が表示されるので(少なくとも僕が予約したときは)、いい席をツモるまでしつこく繰り返すのがよい。
* 一番高い席だとCブロック前方が確定しているが、数が少ないので売り切れがち。2番目に高い席で運よくCブロックを確保できたなら(僕らがこれ)、一番高い席とほぼ同じ。
* 途中の30分の休憩はちょっと余計だが、観客に子供も多いことを考えると仕方ないかも。
* 劇場内のショップはまだ品揃えが少ない。しかもカードはJCBしか使えない。

妻のつわりもようやく終盤っぽいし(9月に入れば新学期なので否応なしに仕事なるため、ここで終わりになったのは嬉しい)、こっちも仕事を加速するつもり。だが最近目の疲れやすさがひどいので気合が入りにくい。

2008.08.23

Workd in Flames

ここ数日、一日の1/3は通常のTactico関係の仕事、1/3はiPhone版の開発、1/3はちょっと気が緩んでゲームで遊んでいる。
ふとしたことから、World in FlamesというHOI2用の大型MODを見つけてしまったのが運の尽き。ついやってしまった。

これはそのサイトにあった紹介用スクリーンショットで、日中戦争の最中の図。
Screensave0xv4


このMODをドイツプレイ(難度は通常の1個上)で一通り流してみたところ、戦闘の決着がつくのに時間がかかるようになった上に師団の移動速度が全体的に上がっているため、防御側は攻撃を受けてから援護に出るので悠々間にあってしまう。さらに爆撃機が大幅に弱体化しているので、攻勢に出るには大量に陸軍部隊が必要になっており、史実どおりにベルギーを突破してマジノ線を迂回するのも無理というありさま。

ちょっとした修正でこれだけ味が変わるとは思わなかった。こういうカスタマイズがあるのはPCゲームならではだ。
傍目にはマニアックなゲームに見えるかもしれないけど、2chではスレが120まで伸びているくらいなのでファンは多いのだろう。PC-98の時代から歴史物シミュレーションゲームは一通り押さえてきたけども、間違いなくこれが最高に面白い。

もう最近の家庭用ゲームは女子供向けが多くて完全にやる気がしなくなってしまった。自分で遊び方を考える余地がないんだもん。遊ばされている感が強くてやってられない。

来年の第三四半期には正規のHearts of Iron 3が出るらしいのでそれをじっくり待つかな。中高生のころを中心にゲームは相当いろいろやってきたが、このシリーズが非対戦型ゲームとしては僕のベストである。

一方iPhone上での開発は徐々に進み、実機で動作確認できる環境が整うとともに、グラフィックがからまないパートはほぼコーディングも完了という段階になった。もうちょっとがんばるとデモができるようになるので、これをどういうビジネスにするかも考えていかないとな。
まだ今の段階ではそれほどiPhoneの普及台数は大したことはないけども、使っている人は熱意が高いこと、ネイティブアプリを持っていることにニュースバリューがあること、を考慮して作戦を立てたい。

2008.08.11

Objective-Cの配列

 Objective-Cと配列についてメモ。ほとんどこれは愚痴なんだが...

 まず、Objective-Cでは、生の配列(int xxx[]; みたいに作るやつ)はあまり使う局面はない。プレーンCと同様、配列サイズがコンパイル時に決定できるときにしか使えないし、オブジェクト配列のとき各要素にreleaseするのが手動だからだ。JavaやC#の配列はサイズは実行時に決定すればよい(実行時に変化させることができないだけ)ので、この差は大きい。

 なので必然的に配列オブジェクトを使うことになる。iPhoneOS/MaxOSXのプラットフォームでは、ご丁寧に配列用のクラスは2種類用意してくれている。NSArrayとNSMutableArrayだ。名前を見て分かる通り、配列の中身を変更できるのはNSMutableArrayだけで、NSArrayは構築時に全要素を決定できる場合にしか使えない。
 ところが、「構築時に全要素を決定できる」という縛りを実現するために、コンストラクタで全要素を放り込むAPIしか用意されていないのである。
 可変個引数で、

[[NSArray alloc] initWithObjects:a, b, c]

 みたいな感じだ。いやこれじゃ、依然としてコンパイル時にサイズが決定できる場合にしか使えねーじゃん。あとはCの生配列から初期化するくらいしかできないが、結局「配列作成の実行時にサイズが決まり、あとは変化しない」配列を作るのにはまるで役に立たん。

 なので仕方なくNSMutableArrayを使うことになる。ところが、セレクタ名は長くなりがちなので、ちょっとした配列操作のためにもえらく文字数を消費する。Java/C#なら

a[i] = b;

で終わる簡単な代入ですら、

[a replaceObjectAtIndex:i withObject:b];

と書かにゃならん。げげ。まあXCodeにもインテリセンスはついているのでこれをフルにタイプする必要はないが、でもなんだかなあ。

 あと他の不満としては次がある。

* 配列要素にnilがあってはならない(そうしたい場合は少ないが、たまにはある)
* 配列要素はすべてid型(タイプセーフにするのはカテゴリとマクロで下のようにすれば何とかなるが、プリミティブ値が直接突っ込めないのでint[]相当のことをやらせるためにNSValueを使わないといけないのはつらい)


#define TYPESAFE_ARRAY_DECL(TYPE, SELKEY) \
@interface NSMutableArray ( SELKEY ) \
-(TYPE*) get##SELKEY##At:(int)index; \
-(void) set##SELKEY##At:(int)index value:(TYPE*)value; \
@end

* Linked Listが標準ライブラリにないのは勘弁してほしい。そういえば.NET Frameworkも初期バージョンはそうだった。ソフトウェアの何十年の歴史において、本質的なデータ構造は配列・リスト・ハッシュテーブルのたった3つしかない(注:treeはリストの一種とする)んだから、これが1つでも欠けるのは困る。
* XCodeのインテリセンスはもうちょっと賢くなってほしい。型を見ているような見ていないような微妙な挙動をする。
* 少し複雑なマクロを書いているとXCodeのエディタがよくクラッシュする。VisualStudioやEclipseに比べるとXCodeはちょっといまいち。

 開発作業は進んでいるが、少し作業するとすぐ分からないこと/気になることがでてきて、それを調べる寄り道が多い。特に、調べものをしてるうちにWikipediaに辿り着いた場合、関係ない分野にもたくさんリンクが張られているのでついクリックして読んでしまう。昨日も、Objective-Cのことを調べていたはずなのに気がつくとなぜかナチスドイツ陸軍の戦車の記事を読んでいたぜ。

 他にも、後で便利なように小技マクロやクラスを書いたり、そのテストケースを書いたらまた調べたいことが出てきて、そのうちに別のアプローチを思いついてコード書き直して実験して...の繰り返し。Yak Shavingってのはこれのことだな。

2008.08.06

Objective-Cのここが嫌い

 iPhoneOSというプラットフォームとObjective-Cという言語にも徐々に慣れてきた。
 しかし、まだiPhone関係は具体的なビジネスの話にはなってない(それはデモができるくらいになってから営業活動を開始する予定)ので、毎日こればっかやるわけにはいかない。地道に金を稼ぐ仕事も大事で手は抜けないからね。
 面白さだけで判断すればiPhoneだけやってたいなあ。来週妻の実家へ行く(お盆なので)のだけど、当然Mac持参で開発続行です。

 さて、今日はObjective-Cのイヤな点を書いてみる。僕はC++でプログラミングの基礎を学び、その子孫(Java/C#)の言語で多くの仕事をしてきたので、C++ファミリーの常識と異なるところで非常に違和感を覚える。異教徒の国にやってきたわけだからな...

●「ぬるぽ」がない
 やはり最大の衝撃はここ。null参照のオブジェクトに対してメソッドを呼んだ場合、C++ではクラッシュ、Java/C#では例外が飛ぶ。が、Objective-Cでは単にその呼び出しが無視されるだけである。なので、非nullを想定してるところでnullが入っていた場合、実行がかなり進んでから異常に気づくことになるので、デバッグ効率が悪い。
 これは積極的にassertを入れるしかないのかなあ。これはメリットがよくわからない仕様だ。

●引数の型のみが異なるセレクタ
 セレクタについて不満な点。引数の型のみが異なるセレクタが異なるクラスに定義されていると、全く関係のないクラスであっても、idに対しての呼び出し時にコンパイラが警告を出す。出るのは警告だけだし動作は期待どおりになるんだけど、やはり気持ちが悪い。

 このようなことは実際にはすごく簡単に起きる。
 機能上関係のない2つのクラスA,Bがあって、それぞれインスタンスを一意に識別するキーとしてAはint、Bは文字列を使うとする。で、

Aでの宣言:
-(id) initWithKey:(int)key;
Bでの宣言:
-(id) initWithKey:(NSString*)key;

 というようなメソッドを書いた時点でもうこの制約にひっかかる。これはキツい。
 型まで一致してれば問題はないのだけど、さすがに全部の引数をidにするわけにもいかんしな。回避するには initWithIntKey みたいに型名を意識したセレクタ名にするしか思いつかない。id型に対しての呼び出しのときだけだからいいんじゃないの、と思う人もいるかもしれないが、[A alloc]とした時点で返るのはidなのでコンストラクタ系はほぼ全部対象になる。
 なにしろ、iPhoneOSのフレームワーク内を含め、全クラスの全セレクタに対して重複不可なので、うっかり重複することは非常によくありそうだ。


●配列の使い勝手の悪さ
 これも僕は相当にブチ切れている(不便さに怒ってマウスを机に叩きつけたことが3回はある)のだけど、長くなるのでまた今度。


 しかし救世主もいる。

 id型とセレクタを駆使すればほとんどスクリプト言語に変貌するし、Cと同様の#defineマクロもあるし、カテゴリを使えば既存のクラスの拡張もできるので、これらをうまく使えばJava/C#では不可能なくらいのアクロバティックなコーディングができる。やりすぎれば可読性は最悪になるけど、武器としては強力だ。さらに、iPhoneOSでもできるのかまでは調べてないけれど、MacOSでなら動的にクラスやメソッドを生成できるのでメタプログラミングもOKだ。
 こういうのを駆使して不便に思ったところを快適にするために足回りのコードを整備するのは、将来の開発時間を大幅に節約できるのでおいしい投資だし、どれだけ不便なところに気づくことができるかが腕の見せ所とも言える。

 それにしてもObjective-Cというのは、ほとんどアセンブラのマクロにすぎないプレーンなC言語と、バリバリの高級オブジェクト指向言語であるSmalltalkが強引に合体して奇妙な同居をしている。親和性はゼロ。まさに地獄からやってきた言語だぜ。

 あと、コア部分のヘッダファイルに

* Copyright 1988-1996, NeXT Software, Inc.

 などと書いてあるのを見ると感慨深いね。

« 2008年7月 | トップページ | 2008年9月 »