SSブログ

コーディングスタイル [プログラミング]

こないだからやり始めたBezier曲線による近似。もともとは光線追跡の自分の古いコードを見直さなければならなくなったからなんだけど、古いといってもたかだか2年とちょっとほど前のCocoa/Objective-Cのコード。僕は偏屈で頑固な年寄りなのでたかだか2年前なら違わないだろうと思っていたら、今の自分のコーディングスタイルと全然違っていて、見直すのが煩わしくなって、全部書き直すことにした。どこが違うかというと、自分でも面白いぐらい....

Objective-C2.0とか言って言語仕様を変更してきたのが気に入らなくてしばらく古いスタイルのまま書いていたけど、自分でも気がつかないくらい徐々に染まってきたらしい。昔のスタイルのと違いをあらためて列挙してみると、大きなところでは
  • プロパティ
  • クラス拡張(無名カテゴリ)
  • ARC(Automatic Retain Count)
  • ブロック
があった。

プロパティはドット構文(例えばobject.variable)がC++みたいなんだけど、実態はメソッドが呼ばれていて、C++のコンパイル時点で決定されたインスタンス変数の呼び出しに比べてオーバーヘッドが大きい。一見軽くなったように見せかけてるみたいで、好きではなかった。

でもメソッドを書かなくて済む、というメリットは大きかった。今でも、プロパティへの書き込みメソッドが代入演算子で表されるのに抵抗があるけど、インスタンス変数がたくさんあるクラスの記述では決まったパターンのコードを大量に書かなければならなかったのがすごく楽になる。いつの間にかインスタンス変数の代わりに全部をプロパティで書くようになってしまった。

クラス拡張も気がついたら多用するようになっていた。自分で書いたコードでもすぐなんだったか忘れてしまう。大きなヘッダファイルはたとえ自分が書いたものでも読むのが大変になる。クラス拡張を使ってヘッダにはほんとうに他のクラスから呼ばれるときに必要なものだけを書くことができる。未来の自分にとって優しいヘッダにできるので最近書いたクラスはほぼ全部クラス拡張が含まれている。

ただし、サブクラスを作ったときに、クラス拡張の中で追加されたプロパティにはサブクラスからアスセスできない(コンパイル時点で文句を言われる)。クラス拡張の@interfaceを別のヘッダにしてサブクラスで読み込むと一応できるし、実行時は問題なく動くんだけど、クラス拡張の原則では実装ファイルにクラス拡張の@interfaceがないといけないし、せっかく読みやすくするためにクラス拡張を使っているのに、かえってわかりにくくなってしまう。

インスタンス変数にはあった@private、@protected、@publicといったアクセス制御がプロパティには無くなって、Objective-Cではそういうことには頓着しないスタイルが普通になっている。でもアクセス制御とは別にプロパティをどう使いたいかというのを表現できる手段があっても良かったと思う。weak、strong、nonatomicなどのオプションがランタイムの動作に直接結びついたキーワードばかりなのでプログラマの方をあまり見てないな、という感じがしてしまうのは僕だけだろうか。

ARCも最初は抵抗があった。その昔、古いMacOSからOS Xに転向したときに一番苦労したのがretain、release、autoreleaseの参照カウントによるメモリ管理だった。ルールに従えばそれほど難しくないというのはずっとあとになって気がついたんだけど、最初は実行効率が気になって無駄なretain、releaseを減らそうと、つい考えてしまった。メソッドが返すオブジェクトはそれを呼び出したメソッドが使うために呼んだんだから、その前後で参照カウントを操作するのはおかしいと思っていた。それがいけなかった。

オブジェクトどうしでオブジェクトをやりとりするのがちょっとでも複雑になると僕のやり方はすぐ破綻した。メモリリークや解放されたオブジェクトへのメッセージ送信でバグだらけになった。わずかなオーバーヘッドを気にせず、局所的なルールに従って書くほうがいい、と気がついたのは結構あとになってからだった。Core FoundationのオブジェクトやObjective-C++のオブジェクトや、malloc()で確保したメモリなんかも同じルールに従えば簡単になる、ということにやっと気がついてそれに従ってコーディングするようになったのはOS X10.4あたりになってからだった。

そのすぐあとにガベージコレクションが導入されて、どうしようかなと思っているうちにARCがやってきた。せっかくやっと慣れてきたのに、と悔しくてしばらく無視していた。

retain、release、autoreleaseの局所的なルールは例外がほとんどない(例外は「例外Exception」の扱いだけ)ので自動化もしやすい上に、LLVMという変数間の依存関係の解析に適したコンパイラがAppleの手に入ったことでARCが実用的になった。これは技術的にはすごいことである。それがだんだんわかってくるにつれてARCに転向していった。ARCはルールに従って書いていたのをコンパイラが自動生成するようなもので、ARCを使わないコードともそれがルールに従っていればファイル単位で混在できる。これもキーストロークを減らす役に立ってくれている。

ブロックも同じように最初は抵抗があった。なんといってもスタティックなスコープを実現するために大きなオーバーヘッドが必要になるのが面白くなかった。さらに変数の微妙な生存期間の問題を抱えることになるし、循環参照にも陥りやすい。これは美しくないと思った。

しかし、コールバックといわゆるrefConの組み合わせにくらべると手間がずっと減る。あまりおかしな使い方をしない限り短く読みやすいコードにすることができる。例えばNSArrayのenumerateObjectsUsingBlock:メソッドは(ブロックに適した使い方をすれば)NSEnumeratorやforループよりもずっとシンプルに書ける場合がある。

数年かかってこういった新しいスタイルに懐柔されてきた。新しい機能を使えるようにするAPIの導入は目立つけど、自分のやりたいことに関係なければスルーするだけになる。でもやっぱり、書く手間デバグの手間が減るとか、シンプルになるとか、読みやすくなる、といった新しいスタイルの導入は、派手ではないけどじわっと効いて気がついたら多用している、なんてことになっている。自分でも面白い。

しかしおそらくJavaの扱いと同じように、そのうちAppleはObjective-Cをレガシーな技術としてdeprecatedにしてSwiftがメインの開発言語にするんだろうな。Swiftも今時点では実態はObjective-Cだけど、プログラマから隠蔽される部分が増えて、Swiftなら書けるけどObjective-Cでは表現できない、なんてことも起こってくるだろう。そのころはAppKitもdeprecatedだろうな。

しかし、こんな状態ではAppleと心中だわ。Appleにいつまで付き合うかなあ。かといって今時点では乗り換え先がないもんなあ....
nice!(0)  コメント(0)  トラックバック(0) 

nice! 0

コメント 0

コメントを書く

お名前:
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。

トラックバック 0

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。