Language)をテーマにした「LLイベント」。第7回目となる「LLTV」が、2009年8月29日に東京・中野で開催された。この記事ではプログラムの一部、「大改善!!劇的ビフォーアフター」をレポートする。前編では、Rubyによるfortuneコマンドの“増築”と、Firefox拡張によるslコマンドの実装というネタ系発表をレポートした。中編となる本記事では、C言語にLisp風のマクロを取り入れ、lsコマンドのソースコードを約半分に“修繕”する匠の技をレポートする。後編では、売り場業務が滞りがちだった販売管理システムをbashコマンドで“建て直した”という劇的ビフォーアフターの発表をレポートする。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のコードをCiSEと呼ぶ形式で書き直した例。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に縮むという。「ソースコードの規模が大きければ大きいほど効果が大きい」(川合氏)。マクロの威力を示した川合氏だが、「だからといって今日うちに帰ってすぐに自分のプログラムをマクロで書き換えろという話ではない」と釘も刺す。「マクロは劇薬」(川合氏)だからだ。Halloway著)の中から川合氏は、マクロに関する警句を引用する(ClojureはJVM上のLisp方言実装)。いわく、“マクロ倶楽部”には2つのルールと1つの例外があるという。ルール1:マクロは書くなルール2:それがパターンをカプセル化する唯一の方法ならば、マクロを書け例外:同等の関数に比べて、呼び出し側が楽になるならば、マクロを書いても構わないS式やマクロの強力さを支持するハッカーは多いが、一般のソフトウェア開発で広く使われるテクニックとは言い難い。した事情も含めてか、最後に川合氏は「匠のメッセージ」として次のように述べた。「プログラマであるあなたは、コンピュータに対して万能の神です。言語の制限にぶち当たって言語に使われるのではなく、言語“を”使って、言語と戯れましょう」。劇的ビフォーアフター、匠の技(後編)」では、サイロ化して連携利用が難しかった多数の業務システムを、bashスクリプトとフラットテキスト、多段パイプ処理の組み合わせというUNIX的アプローチで劇的にリフォームしてしまったUSP研究所の當仲寛哲氏の発表をレポートする。World!」プログラムで使われる、「printf()」「main()」関数の中身を、デバッガによる解析と逆アセンブル、ソースコード読解などのさまざまな側面から探る連載。World!」プログラムで使われる、「printf()」「main()」関数の中身を、デバッガによる解析と逆アセンブル、ソースコード読解などのさまざまな側面から探る連載。(2017/7/6)日頃発生する“面倒くさい業務”。簡単なプログラミングで効率化できる可能性がある。Excel」で使えるVBAを紹介する。電話サポートの保留音、世界の主流はクラシック——Genesys調査13カ国で実施した電話サポートの保留音に関する調査結果です。「フードロス」「廃プラスチック」に高い関心——CCC調査エコ・環境問題への関心や関連トピックスへの認知度などを調査しています。