【LLTVレポート】劇的ビフォーアフター、匠の技(中編)
“本物のマクロ”でCのコード行数を半分に!
2009/09/07
毎年夏に開催される軽量プログラミング言語(LL:Lightweight Language)をテーマにした「LLイベント」。第7回目となる「LLTV」が、2009年8月29日に東京・中野で開催された。この記事ではプログラムの一部、「大改善!!劇的ビフォーアフター」をレポートする。前編では、Rubyによるfortuneコマンドの“増築”と、Firefox拡張によるslコマンドの実装というネタ系発表をレポートした。中編となる本記事では、C言語にLisp風のマクロを取り入れ、lsコマンドのソースコードを約半分に“修繕”する匠の技をレポートする。後編では、売り場業務が滞りがちだった販売管理システムをbashコマンドで“建て直した”という劇的ビフォーアフターの発表をレポートする。
Cで書かれたlsのソースコードの問題点
匠の川合史朗氏「Real/Macro Metaprogramming On C」と題した発表を行ったのは、Scheme処理系「Gauche」(ゴーシュ)の開発者として知られる川合史朗氏だ。アカデミックな情報科学の議論から、アセンブラレベルの最適化に至る泥臭いハッカーの実装話までカバーするスーパーハッカーとして知られる“匠”だ。
川合氏が改修を試みたのはlsコマンド(GNUのものではなく、FreeBSD付属のもの)。ソースコードは1141行。川合氏は「非常に素直で読みやすいコードで、C言語で書かれたソースコードとしては優等」としながらも、「LLを使い慣れてスポイルされてしまったプログラマからみると、どうしても不満点が見つかる」と、冗長性やメンテナンス性の悪さを指摘した。
例えばlsコマンドでファイルリストを表示するとき、昇順/降順でソートすることができる。ソートで比較するのはファイル名だったり、タイムスタンプだったりいろいろ。このとき関数ポインタで渡される比較関数として、1つの比較対象につき昇順と降順の2種類が、ペアでcmp.cに定義されているという。これらは関数名と動作が逆である以外はまったく同じ構造で、「新しいソート順を加えたいときに、いちいち2つ書かなきゃいけない」(川合氏)というムダがある。「LLの高階関数が使えれば、関数を引数にとって、その逆の動作をする関数をオンザフライで作れるのですが、C言語では、そういうことができない。とても残念です」(同氏)。類似した構造を持つパターンをくくり出すための抽象化機能が貧弱なC言語の限界、というわけだ。
川合氏が示した問題点の1つ。C言語の抽象化機能が貧弱であるために、似たような関数を2つ別々に定義してある同様に、非本質的な情報がコードに入り込むのも、C言語のソースコードに見られる問題点だという。forループでカウンタを使って配列にアクセスするようなコードや、連結リストをポインタで順にたぐるようなループでは、抽象度の高い言語なら、より端的に意図したとおりの記述が可能。川合氏は「こう書ければなあ」と擬似コードを示すことで、C言語の抽象機能の弱さを指摘した。
ループの抽象化ができないのもCの弱さ川合氏が指摘した3つ目の問題点は、コード中で情報の分散が起こりやすいこと。lsでは多数あるオプションをフラグで管理している。ところが、フラグに関連したコードは、ヘッダファイル、変数を宣言している場所、main関数のオプションパーザと3個所が関係しており、「1つのオプションを付け加えるのにも、最低3個所の改変が必要」と、抽象機能の貧弱さからメンテナンス性が悪い点を指摘した。
オプションスイッチに関するコードが、ヘッダ、変数宣言、オプションパーザの3個所に分散してしまう本物のマクロで大幅リフォーム!
Cで書かれたlsのソースコード。そこにある「冗長性」、「非本質的な情報」、「情報の分散」という3つの問題点に対して繰り出された匠の技は、“本物のマクロ”だ。ここで川合氏がいう本物のマクロというのは、Cのプリプロセッサで処理されるテキスト置換のようなマクロではなく、Lisp風の「コンパイル前に、任意のソースコード変換ができるマクロ」だという。
「(プログラミング言語の)構文なんて飾りです、偉い人には分からないかもしれませんが、ここにいる皆さんには分かってもらえると思います」。リフォームのポイントをこう説明すると、川合氏はおもむろにC言語で書かれたコード片を次々と異なる構文に変形してみせた。関数呼び出しの例としてprint文、制御構造としてif文を、「これは、こう書いても同じことです」とカッコだらけのLispのS式に置き換えると、予想外(もしくは予想通り)の展開に会場からは笑いがわき起こった。
極め付けは、Cのmain関数のコード例だ。「例えば、こういうmain関数を、こう書くこともできます」と、ありふれたCのソースコードが、そこはかとなく原形をとどめながらも、誰も見たことがない不思議な字面のソースコードに変換されるのを見せつけられるに及んで、会場は匠の“荒技”に圧倒されて、大きな笑いに包まれた。匠は「見た目が、ちょっと変わるだけ。慣れればスラスラ読めます」と、こともなげだ。
川合氏が示したCの典型的なコード例
上のCのコードをCiSEと呼ぶ形式で書き直した例。S式でCを書いているという魔法のようなコード変換
S式化されたCのソースコードに会場は笑いを誘われたが、これは“壮大なネタ”などではなく、川合氏が「CiSE」(C In S-Expression)と名付けたまじめな取り組みだ。CiSEによって、CのABIやライブラリ、ハードウェアに近いセマンティクスなど好ましい特徴を変えることなく、抽象構文木を操作してコードを生成するようなマクロを使うことができる。実用性を重視したというScheme処理系のGaucheの実装でも、一部にCiSEを使っているという。
マクロの威力を示すものとして川合氏が示した最初の例は、forループでカウンタを0からインクリメントして配列要素にアクセスするパターンの抽象化。文字列の長さに応じてforループを回すような処理では、「dotimes」と名付けたマクロによって、非本質的な一時変数はコードから消失し、カウンタを0で初期化するという低レベルの処理も隠蔽できることを示した。CiSEでは、一時的に必要となるC上の変数などは自動的に通し番号で管理され、名前の衝突が起こらないよう配慮されているという。
マクロを使ってループを抽象化した例。一番上が元になるコード。真ん中がそれをマクロで展開した表現で、それをC言語に変換するといちばん下のコードが生成できるこのほかマクロを使うことで、繰り返しパターンの除去や、本質的な処理のくくりだしによる冗長なコードの整理、DSLのように宣言的構文で複数ファイル上の該当個所にコードを生成して、分散していた情報を1個所に集めるなどの抽象化テクニックを川合氏は次々と披露(この間、会場には劇的ビフォーアフターのBGM)。オリジナルのCの関数をすっきりと整理していくことで、全体のコード行数を約半分に縮めることに成功。ソースコードが短くなっただけではなく、同系統の機能の追加が容易になったほか、パターンの再利用性が高まるといったメリットも加わったという。
もしこうした改修を本当に行ったとして、果たしてlsコマンドをメンテナンスするCの住人たちが暮らしてゆけるのかという疑問は残るが、劇的なビフォーアフターであることは間違いない。
オプションスイッチ処理関連のコードは、オリジナルのCでは3個所に分散していたが、マクロを用いたDSLによって各オプションは1行の宣言で済むように
lsコマンドのソースコードを匠が書き換えた結果、約半分の行数に!言語「に」使われるのではなく、言語「を」使おう
マクロを使うことで一般にソースコードの行数は数分の1に縮むという。「ソースコードの規模が大きければ大きいほど効果が大きい」(川合氏)。
マクロの威力を示した川合氏だが、「だからといって今日うちに帰ってすぐに自分のプログラムをマクロで書き換えろという話ではない」と釘も刺す。「マクロは劇薬」(川合氏)だからだ。現在翻訳作業中の書籍「Programming Clojure」(Stuart Halloway著)の中から川合氏は、マクロに関する警句を引用する(ClojureはJVM上のLisp方言実装)。いわく、“マクロ倶楽部”には2つのルールと1つの例外があるという。
- ルール1:マクロは書くな
- ルール2:それがパターンをカプセル化する唯一の方法ならば、マクロを書け
- 例外:同等の関数に比べて、呼び出し側が楽になるならば、マクロを書いても構わない
S式やマクロの強力さを支持するハッカーは多いが、一般のソフトウェア開発で広く使われるテクニックとは言い難い。こうした事情も含めてか、最後に川合氏は「匠のメッセージ」として次のように述べた。
「プログラマであるあなたは、コンピュータに対して万能の神です。ですから、言語の制限にぶち当たって言語に使われるのではなく、言語“を”使って、言語と戯れましょう」。

「LLTVレポート 劇的ビフォーアフター、匠の技(後編)」では、サイロ化して連携利用が難しかった多数の業務システムを、bashスクリプトとフラットテキスト、多段パイプ処理の組み合わせというUNIX的アプローチで劇的にリフォームしてしまったUSP研究所の當仲寛哲氏の発表をレポートする。
関連記事
情報をお寄せください:
- 構造体の便利な用途、インターフェイス入門 (2010/3/10)
継承機能を排除したインターフェイス機能でダックタイピングが可能となった。サンプルで確かめてみよう - プライベートモードの履歴状態 (2010/3/1)
仕事に集中できるときと、なかなかできないとき、ありますよね。状態遷移図で考えてみよう - Goのswitch文で解くFizzBuzzと構造体のイントロ (2010/2/25)
Goではif文と同等の制御構造をswitch文で表現できる。試してみよう - SQL4GでGAE+Railsを体験しよう (2010/2/23)
Google App Engine上でRDBMSを使ったRailsアプリケーションを構築する。環境設定手順を詳しく解説
|
|
スポンサーからのお知らせ
- - PR -
| 「特権ユーザー」の事件を防げ! 万能権限を持つユーザーの管理方法とは? New! |
| 仮想環境の構築とデータ保護の特効薬?! 実績と信頼性の高いパッケージで安心運用 |
| 仮想環境のバックアップもこれまでどおり 「まるごと取ってまるごと戻す」簡単運用 |
| おばかアプリ選手権、第4弾開催中!! ムダにカッコよくてくだらない作品求ム! |
| 社内ファイルサーバを“クラウド”に統合 VPN直結「クラウド型ストレージ」を紹介 |
| その数、なんと400台以上! グループ内 サーバの「統合管理」によるメリットは? |
| 美人!? まあまあ? 気になる いやし系!! PV急増で「美人時計」がとった手段とは? |
| 進化を続ける富士通ストレージETERNUS DX 製品開発者の自信を裏付けるものとは何か |
| 運用管理の課題を“2つの観点”から分析 ユーザー満足度の高い「仮想環境」とは? |
お勧め求人情報

**先週の人気講座ランキング**
〜Java編〜
| ◆ | TomcatやJBossなどAPサーバ環境に関する 情報を集約! “業務”用APサーバ大百科 New! |
| ◆ | 一気に解説! 最新のクラスタストレージ 「RAIDを超えたストレージ基準」……など New! |
| ◆ | クラウド的ユーザー体験の変化は脅威か? 仮想化技術を使いこなす運用管理術を紹介 New! |

| ◆ | 上司や部下、部署内メンバーとの情報共有 を“ガラッ”と変えるコラボツールとは? New! |
| ◆ | おばかアプリ選手権、第4弾開催中!! ムダにカッコよくてくだらない作品求ム! |
| ◆ | 社内ファイルサーバを“クラウド”に統合 VPN直結「クラウド型ストレージ」を紹介 |

| ◆ | Twitterのアカウントはなぜ突破された? メールによる新手の攻撃手法とその対策 |
| ◆ | もう仮想化のお試しフェイズは終わりだ! Hyper-V 2.0が基幹システムも仮想化 |
| ◆ | 美人!? まあまあ? 気になる いやし系!! PV急増で「美人時計」がとった手段とは? |

| ◆ | クライアント企業から求められる人材 ⇒IT技術と経営戦略を併せ持つ「戦略家」 |
| ◆ | .NET編集長が実践する「技術情報検索術」 サンプル・コードを簡単に探す“技”は? |
| ◆ | 業務効率と情報セキュリティ対策を両立! 手間なく確実に機密情報を守る方法とは? |

| ◆ | 進化を続ける富士通ストレージETERNUS DX 製品開発者の自信を裏付けるものとは何か |
| ◆ | 運用管理の課題を“2つの観点”から分析 ユーザー満足度の高い「仮想環境」とは? |

| ◆ | 【CTC事例】約30の基幹システムを統合! 膨大なバッジジョブを制御した方法は? |
| ◆ | 仮想化すればコストは削減できるか? 仮想化に必要な「3つの視点」を解説する |
| ◆ | その数、なんと400台以上! グループ内 サーバの「統合管理」によるメリットは? |






