プログラミング小噺三題その2

Objective-Cに嵌る

Objective-CはCの系列なのでクラスを宣言するヘッダファイル(.h)とクラスを実装するソースファイル(.m、.mm)がある。同期通信を非同期通信に置き換える改造(元は私のコードではない)で、色々書き換えてるうちにどうにも全く動かなくなった。以下、クラスの宣言はヘッダファイルでする必然性はないが、機能のモジュール化等の現実のプログラミングの流儀を前提とした話なので、クラスの宣言=ヘッダファイル、ということで了承願いたい。

詳細に調べて判明したのは、ヘッダファイルにメソッドの宣言があって、ソースファイルに実装がなくてもXcodeではビルド・サクセスとなり、リンクエラーにはならないということだ。C++はオブジェクト指向言語としては偽物なので、存在しないのに呼ばれてるメソッドはリンクエラーになるのだが、Objective-Cはメソッド呼び出しがきちんとダイナミックになってるので実行時に解決することになる。で、解決できないとどうにも全く動けない。

問題のソースファイルをコンパイルするとちゃんとWarningが出ていた。ヘッダファイルに書いてあるメソッドが見つからないぞと。綴りが間違ってた。Objective-Cはヘッダファイルに宣言のないメソッドはクラス内でのみ使える、C++でいうところのプライベート扱いになる。それが仇になった。綴りを間違えたメソッドは正当にプライベートメソッドになっていた。C++だとプライベート(クラス内でのみ呼べる)だろうとパブリック(どこからでも呼べる)だろうとヘッダファイルに書かないといけないので、綴りの間違いはそもそもコンパイルエラーになる。Objective-Cはヘッダファイルに記述することなく自由にプライベートメソッドを書ける、すなわち再コンパイルが発生しにくいという、マシンパワーが貧弱(最初のNeXTはMC68030)な時代の要請が言語仕様に反映されており、コードの改造には微妙に不便だと再認識した。わざとコンパイルエラーを発生させてそこの記述を書き換えるというのが昔ながらの常套手段だからだ(なので、LLで書かれたプログラムの改造は勘弁して欲しい)。そういえば以前も同じように綴り間違いで慌てたことがあるのを思い出した。

AppleのAPIリファレンスに憤る

AppleのAPIリファレンスのページでNSURLSessionを調べる。downloadTaskWithURLメソッドをブラウザのページ内検索で探す。見つからない。目で探すとある。まさかとdownloadTaskWithURLを選択してコピー、テキストエディタにペーストするとdownload Task With URLとなる。アチャァ。しかも単なる空白が埋められてるのでなくU+200Bだ。ゼロ幅スペースだよこれ。これ決めた人はプログラマに恨みでもあるんですか? 頭おかしいザマス。Appleの製品向けにプログラムなんて作るなってことかいな。
Firefoxでは見つからないがSafariでは見つかる。Edgeでは見つからないがChromeでは見つかる。WebKit系の方が優秀ですよとでも言いたいのか。downloadTaskWithURLとdownload Task With URLは違うだろ、メソッド名は分解して良い何かではない。

OCamlnetに落胆する

「OCamlnet Http_client」でWeb検索すると、Http_client.Convenienceを使ってみた系の頭の悪い話ばかりでウンザリする。Cookieをセットしたりとか細かく制御したいからプログラムを書くんであって、Http_client.Convenienceでは仕様が大雑把過ぎて使えない。まだしもwgetの方が色々できる。
Http_clientの使い方はHttp_client.pipelineが関係してることまでは突き止めた。つうかマニュアルのHttp_client.pipelineのところにExampleが書いてある。ダウンロードのプログレスを出したいんだが、どうもよく分からん。プログレスが出せないならHttp_client.Convenienceでも同じ。

OCamlnetを調べて判ったのは、ダウンロードするときにどのくらい済んだのかの経過を表示したい、という私の目的はちょっとやそっとでは達成できないらしいこと。OCamlnetはなるほど壮大なフレームワークのようで、色々取り揃えているようだ。だが、ガイドの説明にて「The Netchannels tutorial – strongly recommended read!」なんて書いてあるから読んでみたが、単に独自のI/Oデスクリプタの説明だった。Http_clientを調べてる私には一切無関係。
単にhttps接続されたWeb上のファイルをダウンロードしたいだけだってのにpipelineやらcontextやらtransportやらequeueやらengineやらあまりにも普通名詞過ぎて意味不明な独自概念が目白押し。あぁ、なんだ、世界系だったのか。こういうのチマチマ構築するのって楽しいんだろうなぁ。結局経過表示をする方法は発見できなかったわけで、縁があったらまた会いましょう、さようなら。せめてPythonのurllib2とか.NETのWebClientくらいに扱いやすければ文句もないんだが。

結局自分でUnix.socketを使って書いたHTTP GETをするコードを元に、Socket通信をOCamlの外部ライブラリのSslに置き換えることで実現。さらにはファンクターにして、httpとhttpsでコードを共有した。C++なら仮想関数で実現するようなことはOCamlではファンクターで合ってるんだろうか。五十嵐淳さんの入門書に「一部だけ異なる似たようなモジュールを何度も書く面倒をなくし」とあるから多分合ってるんだろう。