読者です 読者をやめる 読者になる 読者になる

コードの読みやすさからプログラミング言語を見つめる。

設計

 ※ ずっと頭の中で妄想としてあって、そろそろ邪魔になってきたので一度ここに書いておいて僕はこの件はさっぱり忘れようと思う。

 プログラミング言語は今日び星の数ほどあって、それらを比べる手軽な指標として可読性があるように思う。プログラムソースは人が読むので、読みにくいよりも読みやすいことが良しとされる。
 しかしプログラムソースが連続した文字だけで表現されるので、文字ストリームが持つ表現能力以上の表現はできない。どだい可読性向上の欲求が満たされることなどありえないんである。だというのに、プログラマが可読性を求めて止まないから、多様な記述性を確保するために言語仕様をガッチガチに固めないといけなくなる。その結果、こういうことになる。


・ちょっと記述を間違ったんだがそれに気づかず、
 コンパイル通っちゃうが思うように動かない。
・データへのアクセスルートを絞るようなコードを書いたつもりだったが、
 実は未知な文法を使えば存外簡単にアクセスできた。
・1 行のコンパイルが通らず、それがなぜ間違っているのか理解できず、
 そのためだけに膨大な勉強時間が要る。
 その一方で、一度リリースされたライブラリには素晴らしい機能があり、「◯◯を使えば☓☓ができる」というメリットが謳われるわけで、結局のところプログラマが行うのはそれらを組み合わせて繋げることだけだったりする。材料は手元に揃っているのにユーザーが求めるアプリケーションというゴールに辿りつくまでやたらと長い時間がかかってしまう。

 もちろん言語仕様ばかりが問題の原因だとは思わない。でもプログラマがこだわりやすいポイントであるからこそもっとよく出来るんじゃないかと関心がそっちに向く。
 こういうのを解決しようとする試みに言語内 DSL があると思う。
例えば url を分かりやすく表現する DSL を利用した Scala のサンプル。

import Web._

val blog = http :/ "www.codecommit.com" / "blog"
blog.get      // => XML fragment

val search = http :/ "www.google.com" / "search" ? ("q" -> "Daniel Spiewak")
search.get    // => XML fragment

 ソース先頭で import してる「Web」の実装は 『djspiewak / linguistic-programming』 で見れる。これがないと Scala の標準の文法の範疇では上記ソースはコンパイルエラーである。「Web」の実装の中で http という名前のオブジェクトや「:/」「/」などの演算子をオーバーロードが定義されていて、上の例がコンパイル通るようになっている。可読性は確かに上がるように思う。
 しかしこれはあくまで文字ストリームに並べる意味の種類を限定するためのテクニックに過ぎない。例えば幾何学図形の描画処理やダイアログに並べるボタンのレイアウト調整処理などを行う言語内 DSL を開発しようとすると、かなり高いスキルが無いと「使い易い DSL」にはならない。そもそもその DSL の文法を覚えないと読み書きできない。ただでさえソフトウェア開発では覚えないといけないことが多いというのに、DSL の数だけ文法を覚えるなんて相当なドMのやることである。
 さて「使い易い」と書いたが、では使い易いとはどういうことなのか。脊髄反射で「最も使いやすいものは人によって違うんだからプロセッサが飛躍的に進化して開発環境が AI を搭載しない限り無理ゲ」って言う人がたまに居るがそれはまた数十年後に議論するとして横に置いておく。とはいえ、使い易さは、その対象がプログラマのイメージ・設計の意図にどれだけ近い表現ができるかにかかっている、という点は押さえておいて続ける。

 ・絵を描くときにコマンドプロンプトで座標をタイプしたりせず、描画用のアプリを使う。
 ・Twitter のタイムラインを見るときにコマンドプロンプトAPI 呼び出しをしたりせず、クライアントアプリを使う。
 ・家計簿をつけるときにはコマンドプロンプトで項目をタイプしたりせず、家計簿アプリを使う。

 これと同じように、プログラミングにおいても「局所的に専用のアプリを使ってプログラムを描き、コードに変換し、加筆修正もそのアプリ上でやる。」ということをしたらいいんである。その最たる例がリソースエディタだろう。リソースファイルの記述を専用のアプリで行い、プログラム側からはそれを呼び出して動かす...、ということを現代のプログラマは普通にやっている。いわゆるコードを書き殴るプログラミングと異なるのは、リソースエディタは勉強しなくてもだいたい使えるということである。これは勉強しなくてもいい、取扱説明書が要らない、使ったあとは忘れたって問題ない、というメリットを生む。こんなにいいことだらけなんだからこれをもっとプログラムと密接に結び付けられるように強化すべきである。そもそもプログラミングはユーザにメリットをもたらすようなソフトを生み出すことがその目的である*1。精密かつ厳格に砂糖を振りかけたラッピングライブラリを職人プログラマが作り上げては、それを利用するコードではさらに巧妙な字下げや暗黙変換を駆使してソースコードアスキーアートのように彩ったとしても、実現の難しさの割に得られる生産性はたかが知れているんである。こういうのをいくら頑張ったってユーザーの利益はさして変わらない。

 つーわけで、プログラミング言語仕様の策定にあたっては高い可読性への追求はそもそも不要だと思う。言語仕様を改良して得られる可読性よりも外部アプリで演出できる可読性のほうが高いからである。

 あー、「アプリを作るアプリを作るってこと?それなんて RPG ツクール?」とか言われそうなので補足しておくと、文字ベースの汎用プログラミング言語が何かあって、それを部分・部分で専用アプリを使って編集する、という妄想なのであしからず。
 
 これでようやく言語仕様の複雑さを減らす動機ができた。言語仕様の策定に余裕ができるはずなので、その余裕を外部アプリと連携しやすいようなしくみづくりに投資することを考える。

 外部アプリが連携しやすいというのはつまりコンピュータにとって読みやすい言語にするということである。人によって読みやすいかどうかはどうでもよくってコンピュータにとって読みやすければいい。... とはいえバイナリデータまで落としこむとポータビリティが落ちるのでテキストデータであるという縛りは現行のままとする。これまでリリースされてきた言語の仕様策定に使われたテクニックが、別の目的のために活かされる。例えばこんなの。(Java)

class Item1
{
    public Item1( int price, int weight );
    // ⇒ new Item1( 100, 200 );
}

class Item2
{
    public Item2( Price price, Weight weight );
    // ⇒ new Item2( new Price( 100 ), new Weight( 200 ) );
}

 Item1 の生成より Item2 の生成の方がコードが長くなる。しかしコンピュータにとっては Item2 の方が都合が良い。引数の意味が明確になったからである。Item1 のコンストラクタは引数の一つ目に渡すか二つ目に渡すかで price になったり weight になったりするが、Item2 のコンストラクタは渡す値の順番はどっちでもいいようにコンピュータによって解決させる機能が期待できる。コンピュータが適切に意味を解釈できるのであればグラフィカルなアプリによって Java の文法を知らない人が Item2 のコンストラクタに適切な引数を渡せるようになる*2

 この例はクソみたいに些細な差異にしかなってないので全然嬉しくないけど、この調子でアノテーションジェネリクス、証明などで培われたコンピュータの使い方をソースコードのプレゼンスに投資するように仕向けることで、より現場の開発は楽にできるはずである。
 プログラミング言語の仕様策定の目標を、
 「可読性が高く、冗長さが無く、簡潔に書けてマルチパラダイムなもの」
から
 「最低限人が読み書きできる程度の可読性をキープしつつ、コンピュータに読みやすく、記述されている意味が厳密なもの」
へと変化させるわけだ。
 
 ハードウェアの進化によってただでさえ並列プログラミングが求められるようになってきたし、ユーザーからの要求は複雑さを増すばかりである。「ユーザーが喜ぶように、使いやすいように。」とアプリ開発に精進するプログラマたちが、文法ごときに議論のネタを持ってかれたり人件費を浪費したりして、あまりにコンピュータの恩恵を受けられない環境下にいるなんて嫌なんである。

 ... と偏見プログラマは思っていたんだが、こうして blog のエントリにようやく書けたので、この妄想のことは今日限りさっぱり忘れるとしよう。

*1:研究・勉強・趣味とかは別として

*2:いやもちろんそんなことばかりをやりたいわけではないですが勿論!!!