Island Life

< 主観で何が悪いのだろう | ヘッダにstatic member >

2010/07/28

Gaucheにdocstringが無い理由

gauche-develあたりで昔書いたような気もするけど、日本語でも書いとこう。

gauche はドキュメンテーションに不安があるな。EmacsLisp に慣れてるからだろうか。
コードのすぐ側にドキュメント文字が置けるのは大きなメリットだと思う。

Lisp系言語は昔から、関数の中にドキュメントを書けて、REPLからいつでも参照できる 機能を持っていた(docstring)。Gaucheは敢えて伝統を破って、その機能をつけていない。 今後もたぶんつけない。

主な理由はふたつ。

  • Gaucheは効率的なスクリプトエンジンであることを第一の目的にしている。 つまり、毎回実行の度にソースが読まれてパーズされることが前提。 docstringは開発時には役に立つけれど、実行時にはただのオーバヘッドである。 (プリプロセスしてdocstringを外したスクリプトを作っておくという手はあるが、 プリプロセスするくらいなら事前にコンパイルしたって同じ手間で、 その手間をかけないからこそのスクリプトエンジンなわけで。)
    ある意味コメントもそうなんだけど、コメントのパーズの方が文字列のパーズより軽い。
  • そもそも、コードとドキュメントを近くに置くのは良くないと思っている。
    • ちゃんとしたドキュメントを書こうとすると結構な分量になり、コードと混ざって コードがひどく読みにくくなる。例:大きなJavaのプロジェクトのソース。 (但し、Javaは設計方針としてコードを読むことよりも既にあるAPIを呼ぶことの方を 重視しているふうであり、そうであるならばコードの読みやすさを犠牲にしても それなりのAPIドキュメントが確実に生成されることを重視するのは理にかなっている。 Gaucheの方針は違うけど。)
    • 読みやすいドキュメントというのは構成も含めて考えられるべきだが、コードに混ぜて 書こうとすると全体の構成がコードに引っ張られてしまう。(KnuthのWEBシステムは ドキュメントの構成が先にあり、コードはシステムによって並べ替えられる。) 個々の関数のクイックリファレンス程度なら関数ごとに独立してるからいいんだけど、 それとは別にちゃんと構成を考えたドキュメントはどっちにしたって必要。
    • コードとドキュメントはひとつの抽象物を別々の視点から記述したもの。 より記述されるものを明確にするには、なるべく別の方向から記述した方が良い。 コードとドキュメントを一緒にすると、似たような視点からの記述になってしまがち。 (Cf. コードと別にドキュメントを書く意味)。
    • これはワークフローによるけど、Gaucheみたいにドキュメントのソースが 多国語化前提の場合、コードに埋め込むのはやりにくい。(もっとも、ソース内に 全言語を持っておくというGauche方式は言語数が増えると破綻するので、 コード中のドキュメントは例えば英語で統一しといてgettext式に 翻訳を別の流れでやるって手はある。)

開発中にすぐにドキュメントが参照できる、というdocstringのメリットについては 別手段で代替可能だ。Emacsを使ってるならソースから一発でinfoドキュメントに飛べるし (例: http://blog.livedoor.jp/naoya_t/archives/51350496.html )、 REPLから (info '関数名) とする手もある。 info 関数については ページ単位ではなくピンポイントで関数の説明に飛べるように工夫したいと思っているけど。 要は、「すぐに引ける」というメリットについては、ドキュメントがどこにあろうが 対応関係が機械的に作れれば何とでもやりようがある。

ただ、問題が無いと思っているわけではない。

  • 標準のドキュメントフォーマットがない。これは、未だ決めかねているという状態。 Gauche本体のように大きなものにはtexinfoが便利なんだけど、全てtexinfoでやれというのは 無理があるし。Perlがpodを、Rubyがrdを持ってるように独自に作っちゃう、っていうのも 車輪の再発明っぽくて億劫。わりと無節操に「色々なフォーマットが使えますぜ」っていうのも Gaucheっぽくてありかなとは思ってるんだけど。
  • 1ファイルで済むようなちょっとしたスクリプトやライブラリなのに、わざわざ別ファイルに ドキュメントを書くというのは確かに面倒。そういう場合はやっぱり ひとつのファイルにまとめておきたくなる。 実行時に負担にならなければいいので、他のスクリプト言語にある __END__ のように loadは何らかのマーカーを見たらそれ以降は読まない、ってことにすればいいんじゃないかとは 思ってる。

(追記2010/07/29 15:55:38 UTC): 別の表現を思いついた。Gaucheの設計方針のひとつは、 SICPにある次の文である。

プログラムは、人が読むために書かれるべきであり、 それがたまたま機械でも実行できるにすぎない。

したがって、言語機能の選択基準の一つは、「いかにコードを読みやすくするか」 という点にある。コードの理解を助ける目的ならば、 関数毎にコメントやアノテーションでその意図 (whyの記述) や 事前/事後条件、トリッキーなコードの説明などを書いておくのは良いことだ。 でもdocstringはコードの理解を助けるための文書ではない。 それはAPIを使う人のための文書だから。

たまたま、APIを使う人のために最適な文書と、コードを理解するために最適な文書が 一致するということはあるかもしれない。でもそうでないことの方が多いだろう。

だとすれば必然的に、docstringとコードを同居させるには、「コードを読みやすくすること」 か「APIを使う人に役にたつこと」のどちらか、もしくは両方を犠牲にするしかない。

Tags: Gauche, Lisp, Programming

Past comment(s)

koguro (2010/07/30 11:08:02):

APIの使い方を知るという場合だと、読み手としては「どんな実装か」より「どんな仕様なのか」が知りたいはずなので、本体のコードではなくテストケース側にドキュメントを書いた方がいいのかなとも思います。ただ、単体テストだとエッジケースが多いので、ちょっと視点がずれるかも。

shiro (2010/07/30 12:07:18):

テストをどう配置するかというのも似た問題ですね。Clojureはソース内に書けるようにしてしまいましたが、non-trivialなケースのテストはやっぱりコード読むのに邪魔になると思います。使用例としてのテスト (black box的な) と、エッジケースをつつくテスト (white box的な) は別扱いにして、前者をドキュメントと合体させるのはありかもしれません。むしろドキュメントをプリプロセスしてテストが走るようになってればいいかな? そしたら例が間違ってるってケースも防げるし。

Post a comment

Name: