査読というお仕事


ときどき私は書籍の監修をさせてもらうことがある。査読をさせてもらうことも結構ある。


査読のときは、私はお金はもらわないことにしているが、この手の原稿を書き慣れていない人の場合、1ページに5箇所ぐらいおかしいところがあるのが普通であって、300ページあれば、少なくとも1000箇所ぐらいは誤字やら脱字やら、説明の仕方がまずいところやら何やらがある。


下手すると自分で本を書く何倍もの時間がかかるのが普通なので、これがノーギャラというのは、本当に割に合わないが、まあ、それでいい本が世に出れば社会貢献につながると思うし、自分の勉強にもなるので進んでやらせていただくことにしている。


私がどういう感じで査読をするか知ってもらうために、私が全く関わってもいない本ではあるが、C++テンプレートテクニックを例にとってみよう。


何故この本を選んだかと言うと、著者の方はお二人ともC++標準化委員会のメンバーなのだから、ある程度C++的に見て正確を期していて然るべきであるというのがある。


そして、επιστημηのおっちゃんは、もう何冊も本を書いているのだから、もっとご自分の原稿に対してシビアな目で見て欲しいと思うし、もうひとりの著者である高橋さん(id:faith_and_braveさん)のほうは、前途有望そうな青年なので、たぶん将来、まだ何冊も本を出すだろうから、これを機にいろいろ考えて欲しいと思うのである。


私が今回選んだのは、pp.34-35。ここで私が気になったのは、以下の部分。C++のtemplateの仕様のなかでもtwo phase lookupは鬼門であり、私なんぞがC++標準化委員会の人に何か言うのはもちろん釈迦に説法だし、私は以下で結構間違ったことを言ってるかも知れない。でもそういう間違いを恐れていては査読は出来ないので、私は査読のときは「私はこう思う」というのを積極的に発言するようにしている。以下でもそういうスタンスで書いてみる。




以下では、「中略」の代わりに"…"を用いる。


0. 「解釈(名前解決)」のように括弧をつけて何かを補足する場合、この括弧を消去しても意味が通らなければならない。この括弧を消去すると、「テンプレートの解釈は、…」となるが、その後ろで名前の解決という説明が2度出てきているので、これだと、テンプレートの解釈についての説明が途中でテンプレートの名前解決の説明にすり替わっていることになってしまう。


よって、最初の文は、「テンプレートの名前解決(テンプレートの解釈)は」で始まるほうが適切だと思う。


1.「テンプレートが定義された時点ではテンプレートパラメータに何が与えられるか決定されていないので」とあるが、「テンプレートパラメータ」という用語は、C++ARMに載っていない。いま調べたら、C++ Templates: The Complete Guideには載っていて、おそらく、C++的には厳密に定義されている用語だとは思うのだけど、詳しく知らない人から「void f(int x)のような関数にしても、xにどんな値が与えられるかはfが定義された時点では決定していないよ」なんて突っ込みが入らないようにするためにも、ここは「テンプレートパラメータとしてどんな型が与えられるか決定されていないので」と書いたほうが親切だと思う。


2.「テンプレートに依存しない名前」と「テンプレートパラメータに依存する名前」となっているが、これでは2つが対等な(対照的な)関係になっていない。前者も「テンプレートパラメータに依存しない名前」と書くべきだと思う。また、依存名の説明がこれだけしかないというのは、すごく不親切。具体的な例を少しでも書けばもっとわかりやすいと思う。依存名としてT::resultとか、いくつかの例示があれば全然読みやすさが違うと思うのだが。


3.「コードの解釈があいまいになる」の意味が不明。コンパイルエラーになるのか、コンパイラによって解釈が分かれるのか、どういうことを言いたいのかこれではわからない。


4. typenameキーワードの使い方をここで説明しているのに、typenameとclassとのキーワードの違いがこの説明ではわからない。typenameキーワードの説明をこの本で初めて説明しているのに、「classまたはtypenameをパラメータの前に付けますが」と文章を続けるのは疑問。「付けます」でいったん文章を終わり、その上で「typenameキーワードの場合には、classキーワードにはない用法があります。」と説明を続けるべき。


そうでないと、「typenameにはもうひとつ重要な用途があります。」と書いてあっても、それがtypenameにしかない用途なのか、classキーワードでもいい用途なのかがわからない。そもそも、その直前で書かれているのは、classでもtypenameでもどちらでも良い例だから、typenameキーワードはclassキーワードで代替可能な用途であって、この説明を見る限り「重要な用途」ではない。だから、「typenameにはもうひとつ重要な用途があります」の「重要な用途」という表現には(この説明の流れだと)違和感がある。


4の下線部は「この例だけを見ればtypenameキーワードはclassキーワードで代替可能なように見えますが、typenameキーワードにはtypenameキーワードにしか出来ない重要な用法があります。」ぐらいのほうが適切。


5.「int p」の部分、サンプルの書き方がよろしくない。この「int p」はずっと後の説明を読まないと意味不明。


6.「pはグローバル変数です」とあるが、このサンプルリストではpは「int p」と「T::result* p;」の2箇所がある。だから「pはグローバル変数です」という説明は誤り。また「pはグローバル変数です」という説明は前後と何のつながりも無く、突発的に出てきて、読者は混乱する。何を説明したいのか、それすらわからない。



7.「引数にstruct Xが引き渡されると」は意味は伝わるが、やや表現がおかしい気がする。「X型の変数xに対して、g(x)のようにこのtemplateを実体化すると」ぐらいではどうだろうか。


8.「pはX::result(=int)へのポインタとなります」とあるが、6.で「pはグローバル変数です」と書いた直後なのに、突然ローカル変数のほうのpについて言及している。このように一つのシンボルや言葉を異なる意味で使うのはなるべく避けたほうが良いと思う。


9. 「struct Y {…};」はYの定義であって、これを10.にあるように関数gに引き渡すことは出来ない。6.のところでも表現に違和感があったが、ここは明らかにおかしい。せめて、6.の表現に倣い、「struct Y {…};のように定義されたYが関数g()に引き渡されると、」と書くべきである。


11.「まったく異なる定義となり」とあるが、何が全く異なる「定義」になるのか?関数gの定義は、少なくともX,Yのどちらが与えられようが変わることは無い。これが変わったら定義ではない。ここは「まったく異なる意味になり」と書くほうが適切。ただ、それでも、templateで書かれているのだから与えられる型に応じて実体化され、それぞれの意味(実際に生成されるコード)が異なるのは当たり前だから、やはり何を表現したいのかあまり明確にはならない。この部分は全体的に書き直したほうが良いと思う。


12.「いずれもコンパイルエラーとはなりません」のところにきて、コンパイルエラーとならないのは、pをグローバル変数として宣言してあるためで、「5*p」のpがグローバル変数のpと解釈されるからであるとわかるのだが、この説明ではそれがきちんと伝わらないし、6.の「pはグローバル変数です」は、ここに入れるべき説明だと思う。


また、このようなグローバル変数コンパイルエラーとならないようにするためだけにサンプルコード上で意味なく定義して、ここで「コンパイルエラーとはなりません」と説明をするよりは、こんなグローバル変数は最初から宣言せずに、「5*pと解釈され、その結果、pという変数が宣言されていないので、コンパイルエラーになります。(ただし、pという変数がグローバル変数として宣言されていた場合などは、コンパイルエラーになりません。)」と説明したほうが自然だと思う。


あと、「Y::result* p;」という宣言がコンパイルエラーとならないのは、私はよくは知らないがVC++の独自拡張ではなかろうか。「typename Y::result* p;」であるべきなのではなかろうか。このへん、説明をせずに「コンパイルエラーとはなりません」は、まずくないだろうか。


13.「T::resultはTの依存名であり、テンプレートの定義時点ではあいまいなのです」とあるが、何が「あいまい」だと言いたいのかわからない。「テンプレートの定義時点ではT::resultが型なのか数値なのかが曖昧」と書いたほうが紛れが少ない。


14.「依存名をテンプレートの定義時点で解決するために」とあるが、2.の説明で「依存名の解決はインスタンス化時まで遅延されます」と書いてあるのだから、定義時点で依存名が解決されるのが本当だとしたら、この2.の説明と論理的に矛盾する。


そもそもtemplateの定義時点では、templateの関数の中身はコンパイラ的にはノーチェックであってもC++の規約上は許されるはずで、typenameキーワードをつけたからと言って「依存名をテンプレートの定義時点で解決」していると言うのは誤りだろう。C++の用語で「名前の解決」というのがどれくらい厳密に定められているのかは私は知らないけども、「依存名の解決」というのが、two phase lookupの核となる概念なのだから、2.のように説明なしに書くのはまずいし、まして、2.と14.とで説明が矛盾するのは論外だと思う。




とまあ、たった2ページではあるけども、私が見て気になる部分は結構ある。ただし、繰り返しになるが、上の私の意見がすべて正しいとは限らない。そういう風には思わないでいただきたい。査読(ブックレビューと言うべきか)とはこのように自分の意見を著者にぶつけていく作業である。その結果、読みやすく、わかりやすい本が出来るのである。


私がコンピュータ書籍で、この人の本なら間違いなく安心して読めると思うのは、結城浩さんの本ぐらいで、この人の書く本の読みやすさは異常だと思う。どれほど厳しく自分の原稿を見つめたらあれだけわかりやすい本が出来るのか、私にはいまだ想像すらつかない。


新版暗号技術入門 秘密の国のアリス増補改訂版Java言語で学ぶデザインパターン入門増補改訂版 Java言語で学ぶデザインパターン入門 マルチスレッド編プログラマの数学数学ガール数学ガール/フェルマーの最終定理



ところで、冒頭にも書いたように査読は原則的にノーギャラでさせてもらいます。仕事が忙しい時期は引き受けられませんが、私に見て欲しいという人はメールください。(あまりにも間違いが多そうな場合は、実際に私の事務所まで来ていただいてその場でなおしていただくという形になりますが、その覚悟があれば歓迎します。)


あと監修もさせてもらいます。監修はギャラをいただくことにしてます。翻訳本の監修なんかもやらせてもらいます。これも私に頼みたい人はメールください。これまた、私の仕事が忙しい時期は引き受けられませんが。