「C言語でプログラミングする際の覚書」の誤訳箇所
ここでは、C言語でプログラミングする際の覚書の誤訳を列挙します。
参考として、私の翻訳はC言語プログラミングの覚え書き(改訳)にあります。
What follows is ...
×従うべきは
○これから述べるのは
"What follows" で「続くもの」という意味です。ここでの「続く」というのは、現在の文章に続く、つまり「以下に述べること」です。
But they've been accumulating in my head, if not on paper until now, for a long time, ...
×しかし、私の意見は頭のなかにしばらくあったものをまとめたものであり、長らく文章として公開してきませんでした。
○しかし、これらのことは、文書として書いたことはありませんでしたが、私の頭の中に長い時間をかけて蓄積してきたもので、…
"if not on paper until now" これは、"in my head" との対比です。「頭の中にはあったが、文書にしたことはない」という意味です。また、"for a long time" は "they've been accumulating in my head" にかかります。
I've yet to see a good essay on how to plan the whole thing,
×これまでプログラム全体の計画に関しての良い文章は読んだことがありますが、
○全体を計画する方法についてのよいエッセイを読んだことはありませんが、
"yet to" は「まだ…していない」という意味です。文意が完全に逆になっています。
a clear program is not made any clearer by such presentation
×明瞭なプログラムはそのような見た目で成されるものではなく
○明瞭なプログラムはそんな表示をしてもそれ以上明瞭にはなりませんし
"not made any clearer" は「さらに明瞭にはならない」ということです。
... is more to type (or calls upon your text editor)
×タイプ量(あるいはエディタ内で呼ばれる回数)が増え
○タイプ量が増える(または、エディタの助けを求める)ことになりますし
"call (up)on" は「頼る」という意味です。
if you consistently use a naming convention from which np means ``node pointer'' is easily derived
×どの np が "node pointer" を意味しているかがすぐに分かる命名規則を一貫して使っていれば
○np が "node pointer" を指しているということが簡単に導けるような命名規約を一貫して使っていれば
"from which" の "which" は "naming convention" を指しています。
As in all other aspects of readable programming, consistency is important in naming.
×プログラムの可読性に関していえば、命名において一貫性は重要です。
○プログラムの可読性に関するほかの側面での場合と同じように、命名においても一貫性は重要です。
元の翻訳では "As in all other aspects" が訳されていません。
I prefer minimum-length but maximum-information names
×私は最短の名前ではなく最も情報量がある名前を好み
○私は最短の長さで最大の情報量のある名前を好み
「最短であるが、しかし最大の情報量を持つ」という意味です。
They jangle like bad typography.
×悪い印刷のように目障りなのです。
○ひどい表示の仕方と同じように目障りなのです。
最初は、全篇を通して "typography" が「印刷」と訳されていたと思うのですが、その名残でしょうか。
Pointers are sharp tools
×ポインタは賢い道具で
○ポインタは切れ味の鋭い道具で
文字通りの意味です。「賢い」では、あとの「使い方を間違えると…」とつながりません。
If we want the next element's type
×もし次の要素の型が必要な場合は
○もし次の要素の type が必要であれば
原文で type がコード用フォントになっていませんが、文脈から構造体の要素名であることが明らかです。
less effort is expended by the compiler and computer
×コンパイラやコンピュータが展開する労力も減ります
○コンパイラやコンピュータの費やす労力も減ります
"expend"(費やす)を "expand"(展開する)と間違えたのでしょう。
which allows some helpful compile-time error checking that array indices cannot share
×これでコンパイル時に配列のインデックスが適切で無い旨のエラー検出が可能になります。
○配列の添字と違ってコンパイル時の便利なエラー検出が利用できます。
"array indices cannot share" の "share" は、「同じく持つ」という意味です。配列の添字ではエラー検出ができないということです。意味が取れておらず、つじつま合わせになっています。
As a rule
×ルールとして
○だいたいの場合
熟語です。
expressions that evaluate to elements of a data structure
×データ構造の要素を評価するような…データ構造
○データ構造の要素として評価される式
ここでの "evaluate to" は、「評価されることによって…になる」という意味です。
Consider what ... would look like using a compound expression for p
×p の複合的な使い方をしているこのコードが何をしているかを考えてみましょう
○もし p の代わりに複合式を使っていたらどんな見た目になるか考えてみてください
「p の代わりに複合式(例えば、node[i] など)を使ったらゴチャゴチャした見た目になる」ということです。元の訳では意味不明です。
Sometimes it's worth a temporary variable (here p) or a macro to distill the calculation.
×時には一時変数(この場合は p )を使用したり、計算の本質を抜き出すマクロを使用する価値があります。
○計算の本質を抜き出すには、時には一時変数(ここでは p)やマクロを使うことが役に立ちます。
「一時変数」と「マクロ」は並列です。
Procedure names should reflect what they do; function names should reflect what they return.
×プロシージャ名はそれが何をするかを反映すべきです。つまり関数名はそれが何を返すかを反映すべきです。
○プロシージャ名は、それが何をするかを表しているべきです。関数名は、それが何を返すかを表しているべきです。
原文にない「つまり」があるために、実際にはない論理的関係があるかのように見えてしまいます。
A delicate matter, requiring taste and judgement.
×慎重に、経験と判断をもって書く必要があります。
○これはセンスと判断力が必要となる難しい問題です。
コメントの「書き方」ではなく、「コメントを書くこと(書くかどうかを含め)」全体に対するものです。
a symbol table might be implemented ...
×シンボルテーブルは…として実装されているでしょう
○シンボルテーブルは…として実装されるかもしれません
"might" はかなり弱い意味です。
Algorithms, or details of algorithms, can often be encoded compactly, efficiently and expressively as data rather than, say, as lots of if statements.
×アルゴリズム、つまりアルゴリズムの細かな部分は、しばしばデータという簡潔で、効率的で、表現豊かな形に記号化されます。それは、たとえば、多くのif文という形ではありません。
○アルゴリズムや、アルゴリズムの細かいところは、たくさんの if 文のようなもので書くよりも、データとして書いたほうが、効率よく強力に記号化することができることがよくあります。
元の訳は、日本語としてよくわからないものになっています。
A classic example of this is parsing tables, which encode the grammar of a programming language in a form interpretable by a fixed, fairly simple piece of code.
×古典的な例で言えば、表のパースです。これはプログラミング言語の文法を、定形のかなり単純なコード片によって説明可能な形式に記号化することです。
○典型的な例としては、パージングテーブルというものがあります。プログラミング言語の文法を、定型のかなり単純なコードによって解釈できる形に記号化したものです。
"parsing tables" は全体でひとつの名詞です。動詞-目的語ではありません。また、"interpretable" はコードによって「解釈」できる、つまり読み込んでそれに従って動作できるという意味で、「説明」ではありません。
Finite state machines are particularly amenable to this form of attack
×特にこのような問題に取り組むときには有限状態機械が採用されていますが
○この手のやり方としては有限状態機械が特に柔軟に使えますが
"amenable" は「従順な」、つまり「柔軟に使いやすい」ということです。
can be constructed profitably as a data-driven algorithm
×生産的な形としてデータ駆動のアルゴリズムになります
○データ駆動アルゴリズムにすることでいい結果が得られるでしょう
"profitably" は、「利益が得られるような形で」というニュアンスです。
One of the reasons data-driven programs are not common, at least among beginners, is the tyranny of Pascal.
×データ駆動プログラムが一般的でない理由の一つは、少なくとも初心者においては、Pascalによる圧政でしょう。
○データ駆動プログラムが(少なくとも初心者の間で)一般的でない理由のひとつは、Pascalの独裁です。
"at least among beginners" は前にかかります。
This flies in the face of the theories of Turing and von Neumann
"fly in the face of" は「真っ向から対立する」です。これは私も調べたところなのですが、「ここはたぶん熟語じゃないか」というセンスが必要です。適当に訳をでっち上げるのはよくありません。
I cannot recommend an implementation style more highly
×より高度な次元の実装方法を推奨することはできません
○これほどお勧めできる実装スタイルはありません
"highly recommend" という組み合わせはよく聞くものですが、"recommend ... more highly" はその比較級です。「それ以上お勧めできない」、つまり「とてもお勧めできる」ということです。
Maybe that's it:
×以上です。
○きっとこういうことなのでしょう。
これは ":" に続くものに対しての文です。
by construction
×ビルド時に
○組み立て方によって
「組み立て方を工夫することで(多重インクルードを避けられる)」程度の意味です。
but it's usually done wrong in practice
×普通は間違った結果となります
○実際には正しく運用されないものです
"in practice" 実際にやってみると、"done wrong" 悪いやり方で行われる、という意味です。元の訳ではなぜ「間違った結果」になるのかわかりません。
C言語プログラミングの覚え書き(改訳)
Rob Pike
1989年2月21日
Copyright (C) 2003, Lucent Technologies Inc. and others. All Rights Reserved.
Lucent Public License Version 1.02
前書き
KernighanとPlaugerによる“The Elements of Programming Style” (「プログラム書法」木村泉訳)は重要で影響力のある本です。この本にはそれだけの価値があります。しかし、その中の簡潔なルールが、本来意図されたような哲学の簡潔な表現としてではなく、よいスタイルのレシピとして受け取られているように私は時々感じます。この本が変数名は意味を持つようにつけられるべきだと言うなら、名前が使い方を説明するちょっとしたエッセイのようなものであるほうがいいということになるのでしょうか。MaximumValueUntilOverflow
は maxval
よりもいい名前ということになるのでしょうか。私はそうは思いません。
これから述べるものは、融通の利かないルールではなく、全体としてプログラミングの明確さという哲学を促進するような短いエッセイ集です。すべてに同意してもらおうとは思いません。これらは意見であり、意見は時とともに変わるものだからです。しかし、これらのことは、文書として書いたことはありませんでしたが、私の頭の中に長い時間をかけて蓄積してきたもので、多くの経験に基づいています。そのため、これがプログラムの詳細を計画する方法についての理解の助けになればと願っています(全体を計画する方法についてのよいエッセイを読んだことはありませんが、この文章は一部それについて書いています)。もし変わっていると思われても、問題ありません。同意できないとしても、問題ありません。しかし、なぜ同意できないかを考えていただくきっかけになれば、そちらのほうが望ましいことです。決して、私がこう言ったからこう書くということをしないでください。プログラムの中で達成したいことを最もよく表現できるとあなたが考えるようにプログラムしてください。また、それを一貫して、容赦なく行ってください。
あなたのコメントをお待ちしています。
表示の問題
プログラムは出版物のようなものです。プログラムはプログラマ自身やほかのプログラマ(それは数日後、数週間後、数年後のあなた自身かもしれません)に読まれるもので、そして最後に機械に読まれるためのものです。機械は、プログラムの見た目の美しさを気にしません。プログラムがコンパイルできれば、機械はそれで満足です。しかし、人間は美しさを気にしますし、気にするべきです。時々、やりすぎになることもあります。プリティプリントを行うプログラムは、プログラムのどうでもいい細かいところを強調するようなきれいな出力を自動的に行います。これは文章の助詞をすべて太字で表示するのと同じぐらい馬鹿らしいことです。プログラムはAlgol-68 Reportのような見た目じゃないといけない(システムによってはそのスタイルでプログラムを編集するよう強制したりもします)と考える人は多いですが、明瞭なプログラムはそんな表示をしてもそれ以上明瞭にはなりませんし、ひどいプログラムは笑ってしまうような結果になるだけです。
もちろん、表示についての一貫した規約は見た目をわかりやすくするためには重要なものです。インデントは、最もよく知られた、最も役に立つ例でしょう。しかし、見た目がプログラムの意図より目立つようでは、表示が主体になってしまっていることになり、本末転倒です。ですから、古き良きタイプライター的出力で通すにしても、表示上の馬鹿げたやり方には気をつけましょう。装飾を避けましょう。例えば、コメントは簡潔に、バナーをつけないようにしましょう。言うべきことはプログラムの中で、簡潔に一貫性を持って言いましょう。それから次に進みましょう。
変数名
そう、変数名です。名前で重要なのは、長さではありません。重要なのは表現の明確さです。めったに使われないようなグローバル変数であれば、長い名前をつけてもいいかもしれません。例えば、maxphysaddr
のように。ループ内のすべての行で使われるような配列の添字には、i
よりも凝った名前は必要ありません。index
や elementnumber
といった名前をつけるのは、タイプ量が増える(または、エディタの助けを借りる)ことになりますし、計算の詳細よりも目立ってしまいます。変数名が非常に長くなると、何をしているのかわかりにくくなります。これは、表示の問題の一部でもあります。次の二つについて考えてみましょう。
for(i=0 to 100) array[i]=0
for(elementnumber=0 to 100) array[elementnumber]=0;
実際の例では、問題はもっとあっという間にひどいことになります。添字はただの記法です。そのように扱いましょう。
ポインタもちゃんとした記法が必要です。np
が "node pointer" を指しているということが簡単に導けるような命名規約を一貫して使っていれば、np
は nodepointer
と同じぐらい覚えやすいものになります。これについては次のエッセイで詳しく書きます。
プログラムの可読性に関するほかの側面での場合と同じように、命名においても一貫性は重要です。ある変数に maxphysaddr
という名前をつけたら、同種の変数に lowestaddress
という名前をつけてはいけません。
最後になりますが、私は最短の長さで最大の情報量のある名前をつけ、残りは文脈から補完できるようにしています。例えば、グローバル変数は普通、使用時にあまり文脈がないので、名前は比較的内容がわかりやすいようなものである必要があります。このため、私はグローバル変数には maxphysaddr
(MaximumPhysicalAddress
ではありません)という名前をつけますが、ローカルで定義して使うポインタには NodePointer
ではなく np
という名前をつけます。これは感覚によるところが大きいですが、感覚は明瞭さに関わってくるものです。
名前に大文字を入れることは避けています。散文調の文章に慣れた私の目には、大文字は不格好で快適に読めません。ひどい表示の仕方と同じように目障りなのです。
ポインタの使用
C はポインタが何でも指せるという点で変わっています。ポインタは切れ味の鋭い道具です。切れ味の鋭い道具というものは、うまく使うと楽しく生産的になりえますが、間違った使い方をするとひどい傷をつけます(この記事を書く数日前に、私は彫刻刀を親指に刺してしまったところです)。ポインタも例外ではありません。ポインタは危険すぎる、何か汚いものだと思われているため、学術界での評判はよくありません。しかし、私はポインタは強力な記法だと考えています。これは、ポインタは明瞭な表現をする役に立つということです。
考えてみてください。あるオブジェクトに対するポインタがあるとき、それはまさにそのオブジェクトに対する名前であって、ほかのものではありません。些細なことのようですが、次の二つの式を見てください。
np node[i]
一つ目はノードを指していて、二つ目は同じノードを指すように評価されます(ということにします)。しかし、二つ目の形式は式です。あまり単純なものではありません。解釈するには、node
が何か、i
が何か、そして i
と node
がその周りのプログラムの(おそらく明記されていない)ルールによって関連づけられているということを知る必要があります。式だけを取り出してみると、i
が node
の有効な添字なのかを知る手がかりはありません。もちろん、望む要素を指す添字なのかもわかりません。もし i
と j
と k
が全部ノードの配列の添字だとすると、簡単にうっかりミスをしてしまいます。その場合、コンパイラは助けてくれません。特に、サブルーチンに渡すときには間違いを犯しやすくなります。ポインタは単純なひとつのものですが、配列と添字は、それがセットとなるものであることを受け取るサブルーチンのほうで信用しないといけません。
オブジェクトとして評価される式は、本質的にそのオブジェクトのアドレスよりもわかりにくく間違いやすいものになります。ポインタは、正しく使うことでコードを単純にできます。例えば、
parent->link[i].type
と
lp->type
です。
もし次の要素の type が必要であれば、
parent->link[++i].type
と
(++lp)->type
になります。
i
は値が進みますが、式の残りはそのままです。ポインタの場合、進めるものはひとつしかありません。
ここでも表示の問題が絡んできます。ポインタを使って構造体の中を読み進めるのは、式を使うよりもずっと読みやすいものになります。インクの使用量も減りますし、コンパイラやコンピュータの労力も減ります。関連した問題として、ポインタの型はその正しい使い方と関係しているので、配列の添字と違ってコンパイル時の便利なエラー検出が利用できます。また、オブジェクトが構造体であれば、フィールドは型を思い出す役に立つので、次のようなものは十分に意味がわかります。
np->left
添字によって配列を使う場合、配列はきちんと選んだ名前を持つことになり、式は長くなってしまいます。
node[i].left
ここでもまた、例が大きくなれば余分な文字はどんどん厄介なものになっていきます。
だいたいの場合、もしあなたのコードに似たような複雑な式がたくさんあって、それらがデータ構造の要素として評価されるなら、ポインタを注意深く使うことですっきりさせることができます。次のコードで、
if(goleft) p->left=p->right->left; else p->right=p->left->right;
もし p
の代わりに複合式を使っていたらどんな見た目になるか考えてみてください。計算の本質を抜き出すには、時には一時変数(ここでは p
)やマクロを使うことが役に立ちます。
プロシージャ名
プロシージャ名は、それが何をするかを表しているべきです。関数名は、それが何を返すかを表しているべきです。関数は式の中で使われるもので、if
のようなものの中でよく使われます。そのため、適切に読めるようになっている必要があります。
if(checksize(x))
は不親切です。checksize
がエラーのときに true を返すのか、エラーでないときに true を返すのかが推測できないからです。それに対して、
if(validsize(x))
はその点を明確にしているので、将来そのルーチンを使うときに間違いが起こりにくいでしょう。
コメント
これはセンスと判断力が必要となる難しい問題です。私は、いくつかの理由から、コメントをあまり書かないようにしています。ひとつは、もしコードが明確で、よい型名や変数名を使っているなら、コード自身が説明になっているはずだからです。それに、コメントはコンパイラにチェックされないので、正しいという保証がないからです。特に、コードが変更されたあとはそうです。ミスリーディングなコメントは非常に紛らわしいものです。最後に、表示の問題です。コメントはコードをごちゃごちゃにしてしまいます。
しかし、私も時々はコメントを書きます。ほとんどの場合、その次に続くことの説明として使っています。例を挙げると、グローバル変数と型の説明(この場合だけは、大きなプログラムでは必ずコメントを書きます)、あまり見ないプロシージャや非常に重要なプロシージャの紹介、大きな計算セクションの区切りなどです。
有名な悪いコメントというものがあります。
i=i+1; /* i に 1 を足す */
そのもっと悪いやり方もあります。
/********************************** * * * i に 1 を足す * * * **********************************/ i=i+1;
笑うのは早いですよ。笑うのは、実生活で出会ってからでも遅くありません。
コメントでは、かっこいい表示を避けましょう。中心となるデータ構造の宣言のような重要なところは例外としてもいいでしょうが(データに対するコメントは、普通アルゴリズムに対するコメントよりもずっと役に立つものです)、コメントの大きな塊を避けましょう。基本的に、コメントを避けましょう。もしコメントがないと理解できないようなら、理解しやすくなるように書き直したほうがいいでしょう。ここで、次の問題が出てきます。
複雑さ
ほとんどのプログラムは複雑すぎます。つまり、問題を効率的に解くのに必要な以上に複雑だということです。なぜでしょうか。多くの場合、それは設計の悪さが原因ですが、その問題は大きすぎるのでここでは飛ばします。しかし、プログラムは細かいレベルでも複雑すぎることが多いもので、そのことについてはここで書くことができます。
ルール1 プログラムがどこで時間を使うかはわかりません。ボトルネックは驚くような場所で起こるので、ボトルネックの場所を証明できるのでなければ、適当な推測で高速化ハックを入れるのはやめましょう。
ルール2 計測しましょう。計測なしに速度のチューニングをしないでください。計測した場合でも、コードの一箇所がほかの場所に比べて圧倒的に時間がかかっているのでなければ、チューニングはやめましょう。
ルール3 かっこいいアルゴリズムは、n が小さいときには遅いものです。そして、n は普通小さいものです。かっこいいアルゴリズムは大きな定数項を持っているものです。n がよく大きな値になるとわかっているのでなければ、かっこいいことをするのはやめましょう(n が大きくなる場合でも、まずルール2 を使いましょう)。例えば、日常業務の問題では、二分木は常にスプレー木より速いものです。
ルール4 かっこいいアルゴリズムは単純なアルゴリズムよりもバグが起こりやすく、実装が難しいものです。単純なアルゴリズムと単純なデータ構造を使いましょう。
ほとんどの実用的なプログラムでは、次に挙げるリストのデータ構造があれば十分です。
- 配列
- 連結リスト
- ハッシュテーブル
- 二分木
もちろん、これらを組み合わせて複合データ構造を作る覚悟は必要です。例えば、シンボルテーブルは文字の配列の連結リストを含むハッシュテーブルとして実装されるかもしれません。
ルール5 重要なのはデータです。もし正しいデータ構造を選び、物事をうまくまとめれば、アルゴリズムはたいてい自明なものになります。プログラムの中心は、アルゴリズムではなく、データ構造です。(詳しくは「人月の神話」を参照してください)
ルール6 ルール6はありません。
データでプログラムする
アルゴリズムや、アルゴリズムの細かいところは、たくさんの if
文のようなもので書くよりも、データとして書いたほうが、効率よく強力に記号化することができることがよくあります。その理由は、手元の仕事の複雑さが独立した細かい部分の組み合わせによるものであれば、記号化できるからです。典型的な例としては、パージングテーブルというものがあります。プログラミング言語の文法を、定型のかなり単純なコードによって解釈できる形に記号化したものです。この手のやり方としては有限状態機械が特に柔軟に使えますが、何らかの抽象的な入力を「パージング」して何らかの独立した「アクション」列にするようなプログラムであれば、どんなものであってもデータ駆動アルゴリズムにすることでいい結果が得られるでしょう。
このような設計のおそらく最も興味深い側面は、テーブルがほかのプログラムによって生成されることもあるということです。典型的な例でいうと、パーザジェネレータがあります。もう少し身近な例としては、OSがI/Oリクエストを適切なデバイスドライバに割り当てるテーブルによって動いている場合、マシンに接続されたデバイスについての記述を読み込んで対応するテーブルを表示するようなプログラムで「設定」できるでしょう。
データ駆動プログラムが(少なくとも初心者の間で)一般的でない理由のひとつは、Pascalの独裁です。Pascalは、その作者同様、コードとデータを分割することを固く信じています。そのため、(少なくとも元の形では)初期化されたデータを作ることができません。これは、プログラム内蔵方式の原則を定義したチューリングやフォン・ノイマンの理論に真っ向から喧嘩を売っています。コードとデータは同じものです。少なくとも、同じにすることができます。そうでなければ、コンパイラがどうして動くのか説明できないでしょう。(関数型言語はI/Oに関して同じような問題を抱えています)
関数ポインタ
Pascalの独裁の結果には、初心者が関数ポインタを使わないということもあります(Pascal では関数を値に持つ変数を使えません)。複雑さを記号化するために関数ポインタを使うことには、いくつかの面白い性質があります。
複雑さの一部は、ポインタの指すルーチンに渡されます。ルーチンは、同じように呼び出されるルーチンセットのひとつとなるので、何かしらの標準プロトコルに従う必要があります。しかし、それより重要なのは、ルーチンが自分の責任範囲のことしかしないということです。複雑さは分散されることになります。
このプロトコルという考え方は、同じような使われ方をする関数は同じようなふるまいをしなければならないというものです。このことが、ドキュメントの記述やテスト、プログラムの発展をやりやすくしています。さらには、プログラムをネットワーク越しに動かすこともやりやすくなります。プロトコルは、リモートプロシージャコールとしても記号化できるのです。
私の主張は、オブジェクト指向プログラミングの核心となるものは、関数ポインタを明確に使うことだというものです。データについて実行したい操作セットがあり、それらの操作に対して適用したいデータ型のセットがあるなら、プログラムをまとめる一番簡単な方法は、それぞれの型に対して関数ポインタのグループを使うというものです。これは、一言で言うと、クラスとメソッドを定義するということです。もちろん、オブジェクト指向言語にはそれ以上のものがあります。きれいな構文、派生型など。しかし、概念的には、ほとんど変わるところはありません。
データ駆動プログラムと関数ポインタを組み合わせると、びっくりするほど表現力のある書き方ができるようになり、私の経験では、意外な喜びをもたらしてくれることもよくありました。特別なオブジェクト指向言語なしでも、余計な手間なしでオブジェクト指向のいいところの90%を手に入れることができ、結果についても自分でコントロールしやすくなります。これほどお勧めできる実装スタイルはありません。この方法で構築してきたプログラムは、かなりの開発を重ねてもうまく生き残っています。もっとゆるいやり方の場合よりも、ずっといい結果です。きっと、この手法に求められる規律は、長い目で見ると割に合うということでしょう。
インクルードファイル
単純なルールです。インクルードファイルはインクルードファイルを決してインクルードしてはいけません。その代わりに、どのファイルを先にインクルードするべきかが(コメントで、または暗黙的に)言明されていれば、どのファイルをインクルードするべきかという問題はユーザ(プログラマ)に押しつけられますが、ある意味では扱いやすく、組み立て方によって多重インクルードを避けることができるようになります。多重インクルードはシステムプログラミングの癌です。ひとつの C のソースファイルをコンパイルするのに、5 回以上もインクルードされるファイルがあることは珍しいことではありません。この面から言うと、Unix の /usr/include/sys
はひどいものです。
#ifdef
を使ってファイルが 2 回読まれないようにする小手先のテクニックがありますが、実際には正しく運用されないものです。#ifdef
はファイル自身の中にあり、インクルードする側にあるのではありません。結果として、何千行もの不要なコードが字句解析器に渡されることになってしまいます。これは、(良いコンパイラの場合)最も負荷の高いフェーズになってしまいます。
単純なルールに従いましょう。
片付けを始めるコツ
個人的にうまくいった、「片付けを始めるコツ」について書いてみます。
ぼくと同じタイプの人間向けです。
概要を箇条書きにすると、次のようになります。
- 限られた回数の「片付け動作」をする。
- リラックスする。
以上の繰り返しです。
「片付け動作」とは何か。
これは、片付けを進める動作であれば何でもOKです。
例えば、本Aを本Bの上に重ねるとか、重ねた本を動かすとか、紙くずAを拾うとか、その紙くずAを別の紙くずBとまとめるとか、まとめた紙くずA・Bをゴミ箱に捨てるとか。
ここでのコツは、「できるだけ細かく分解する」ということです。
重ねるのと動かすの、まとめるのと捨てるのは別動作です。
で、この片付け動作を3回やる。
例えば、手元の本Aの上に本Bを置いて、その上に本Cを置いて、その3冊の本を本棚の近くに移動する、とか。
ここで、3回も片付け動作をすると当然精神的に疲労困憊しているころなので、敷きっぱなしの布団の上に横になって、お菓子を食べながら漫画を読んでリラックスします。
お菓子は、ピーナッツとかマーブルチョコとか、そういう単位の小さいものがいいです。
個人的には韓国ノリがおすすめです。
漫画は、四コマ漫画等、ちょっと読んだところで止められるやつが向いています。
個人的にはイカ娘とか荒川アンダーザブリッジとかを読んだりもします。
そして、5分ぐらいゆっくり休んだら、次の3動作をやります。
例えば、ゴミを適当に3つ拾って手元に集めたら、それで終わりです。
それからまたお菓子と漫画。
5分で3動作というこのペースで片付けをすると、30分で18動作分片付けが進みます*1。
すると、部屋は目に見えて(部分的に)きれいになっているはずです。
片付け前にゴミや本があった場所にスペースができているとか。
その達成感に浸り、残りは次の機会に回します。
次回以降もこのペースで続けてもいいのですが、どうしても我慢できないぐらいもどかしくなったら、一度の片付け動作を10回に増やします。
休憩時間も、必要に応じて短くします。
1分程度にするとか。
個人的には、この「10回・1分」ぐらいを上限にしています。
ところで、この方法には、ひとつの前提条件があります。
それは、「一人暮らしをしている」ということです。
誰かと一緒に住んでいると、その人の基準で片付き度を評価されてしまいます。
例えば、足の踏み場もない部屋をこのやり方で片付けて、本を20冊ぐらい移動させて足の踏み場がわずかにできたとしても、常人にとってはどちらも手の付けようのないゴミ部屋にしか見えないわけです。
ぼく自身、この方法で部屋の乱雑度をわずかに減らすことができるようになったのに、結婚してからまたできなくなってしまいました。
やる気を尊重して長い目で見てくれてもいいんじゃないかと思うのですが、大きく考えると人類の生存のためには各人が向いていることをやる必要があっただろうし、何かに向いていない人間にはそれをさせないようにする本能があるのかもしれないし(適当)、しかたないですね…。
まあ、そういう他人の評価さえなければ、片付けというのは少しやっただけでもそれに見合った効果があるので、一人暮らしの人にはおすすめです。
*1:21動作じゃないかとツッコみたくなった人は、最後の休憩の後そのまま終わりとすると考えてください。いずれにせよ正確な数字でもないので、素直な計算にしています。
「履く」と「穿く」が面倒なことになったいきさつ
ズボンや靴を「はく」というのは、どう書くか。*1
ご存じの方は多いと思いますが、これはけっこうやっかいな問題なんですよね。
もっとも、「あ、これ正解知ってる」という人もいるでしょう。
ズボン・スカートは「穿く」で、靴は「履く」でしょ、と。
ここで、「じゃあ、靴下は?」となると、問題が急に面倒になります。
というのは、靴下を「はく」をどう書くかについては、辞書によって主張が分かれているからです。
国語辞典
調べてみたところ、靴下を「履く」派と「穿く」派の辞書は、以下のようになっていました。
かなり拮抗していますね。
でも、この問題が複雑になったのはどうしてなんだろうというのが、私にとっては前から疑問でした。
というのは、漢字の意味、つまり中国語での意味を考えると、全部「穿」で問題ないところだからです。
「ズボン等は突き通すから『穿』だ」というのはよく見ますが、近代中国語*3では服もズボンも靴も靴下も、全部「つきとおす」という発想で「穿」を使います。
戦前の表記
実際、戦前(明治から昭和前期)の間は、中国語と同じ発想で、すべて「穿く」を使うのが普通でした。
「股引、脚胖、足袋、草鞋の穿きやう迄」と、まとめて「穿く」が使われています。
その前後を見ても同じです。
日本初の近代的国語辞典といわれる「言海」を見てみると、挙げられている漢字はやはり「穿」「着」です*4。
(二)腰ヨリ下部ニ着ク。「袴ヲ―」脛巾ヲ―」足袋ヲ―」沓ヲ―」穿 着
「腰ヨリ下部ニ着ク」というのはわかりやすい説明ですね。
江戸以前
ただ、この「穿く」というのは主に明治以降のもののようです。
それ以前のものを見ると、はきものについては古くから「履く」が使われています。
たとえば、今昔物語集を見ても「履く」が使われていますし、その後ずっと江戸時代まで、はきものを「はく」というときの主流の書き方は「履く」でした。
足袋についても、浮世風呂などで「履く」と書かれています。
一方で、下半身につけるものについては、「着(は)く」という表記が「田舎芝居忠臣蔵」にありました。
この時代は袴などについても「着る」「着ける」と言うことが多かったようなので、漢字を当てるなら「着」になるのが自然だったのかもしれません。
ただ、カナで書かれている場合も多くあり、「着(は)く」はあまり定着していなかったように見えます。
戦前の「履く」の広がり
江戸時代までは主流だった「履く」ですが、言海には収録されていません。
後で書くように「履く」という表記は日本独自のものなので、この段階で認めることは難しかったのかもしれません。
しかし、その後の辞書を見ると、徐々に「履く」が進出してきています。*5
大言海に「履く」がないのは、「言海」の後を継ぐという性質によるものかもしれません。
この時代の特徴としては、「履く」を採用しているものでも、「穿く」の例文に靴類が挙げられているということがあります。
辞苑では次のようになっています。
は・く[穿く] 腰から下に著ける。うがつ。「下駄を―」
は・く[履く] 足に著ける。足にうがつ。
こちらは広辞林(初版)です。
は・く[穿] 腰より下に著く。うがつ。「袴を―」。「靴を―」。
は・く[履] 足に著く。足に穿つ。
このように、「履く」を項目として挙げるものの、依然として「穿く」は腰から下につけるもの一般に使えるという扱いでした。
戦後の辞書の変遷
戦後は、今につながる「履く」「穿く」の書き分けが広がっていきます。
たとえば、辞海(1947)では、次のように書いています。
(二)[穿]腰から下につける。うがつ。「足袋(ゲートル・ズボン)を―」(三)[履](げた・くつ等を)足につける。
語釈の「腰から下につける。うがつ。」というのはそれまでの辞書と同じなのですが、靴類が例文にありません。
広辞林でも、初版には「穿く」に「靴を―」という例文があったのが、新版(1958年)では消えています。
は・く[〈穿く] 袴・ズボンなどを身につける。うがつ。
広辞苑と新明解の変遷も面白いところです。
広辞苑の初版では、次の画像のように、項目の漢字として【佩く・帯く・穿く・履く】を挙げながらも、使い分けは示さず、語釈としては「(2)腰・腿(もも)・足につける。うがつ。」と「(3)(下駄・靴などを)足先につける。」で分けていて、「足袋」は(2)に分類しています。
それが、第四版(1991年)では次のようになっています。
「足袋・靴下など」を(3)に分類し直したうえで、《履》という表記をつけています。
第三版までは足袋は(2)だったので、意図的に分類し直したということですね。
これは推測ですが、足袋に対して「履く」を使っている例があるため、そうしたということかもしれません。
ここまでは第四版の話なのですが、その後第五版(1998年)で(2)(衣類)に《穿》という表記が加わり、今に至ります。
新明解のほうは、第一版(1972年)は次のような語釈です。
は・く
[一]【〈穿く】
(一)足を保護する物を足先につける。「たびを―・くつを―」〔後者は、履くとも書く〕
(二)下半身や手先を保護する物を身につける。〔着くとも書く〕
「たび・くつ」と「下半身や手先を保護する物」という分類です。
漢字表記については、「基本的な表記は『穿く』で、靴の場合は『履く』とも書く」という、戦前からの流れを汲む書き方です。
それが、第四版(1989年)では次のようになっています。
は・く
[一]【履く】足を保護する物を足先につける。「足袋を―・靴を―」
[二]【〈穿く】下半身や手首から先を保護する物を身につける。「ズボンを―」
それまで「靴」は「穿く/履く」で足袋は「穿く」という扱いだったのが、靴・足袋ともに「履く」という扱いになっています。
これも意図的なものですね。
ここでちょっとずるいなと思ったのは、「靴下」について触れていないというところです。
「足袋」なら古い用例があると言えるので、あえてそちらだけ記載したということかもしれません。
「履」の字義
ここでいったん、明治より前の事情に戻ります。
江戸時代までは主流の書き方として使われてきた「履く」ですが、そのころの主な辞書類で「履」の読みとして「はく」が挙げられることはなかったようです。*7
どうして、実際に使われていた「履く」は冷遇されてきたのでしょうか。
それは、古代中国語(漢文)の「履」という単語に「はく」という意味がなかったからでしょう。
「履」の意味は、主に「くつ・はきもの」「ふむ」の二つです。
ここで少しややこしい事情があります。
「履」には「くつ」という意味があるのですが、これは動詞として「くつをはく」「くつをはかせる」という意味にもなります。
史記の留侯世家に「父曰履我」というところがあるのですが、この「履」は「くつをはかせる」という意味です。
古代中国語では、名詞がそのまま動詞として使われることが多かったようです。
このような品詞転換は、たとえば英語で "pin" という単語が「ピン留めする」という動詞としても使われるのに通じるところがあります。
しかし、この用法はあくまで「『履』をつける」というものなので、漢文の理屈としては「靴を履く」というのはおかしいということになります。
「はきもの」の表記
じゃあ、なぜ「履」が「はく」として使われるようになったのか。
ここで、「はきもの」の表記について考えてみます。
現代の感覚では、「履く物」だから「履物」だというのが自然に感じられます。
しかし、「はきもの」は元々「履」という漢字一文字に当てられる読みでした。
「履」は当時の中国語で「くつ」の意味なので、日本語にすると「くつ」や「はきもの」になるということです。
ですので、日本語の「はきもの」という言葉を書くときには「履」と書けば正しいはずです。
しかし、字義としては正しいのですが、これでは「くつ」との区別ができません。
そのためもあってか、「はきもの」は「物」をつけて「履物」と書かれたようです。
今昔物語集にも、「履物」表記が出てきます。
「はきもの」が「履物」であれば、「はく」は「履く」と書くのが自然です。
その後、「履物」表記は明治に至るまで使われ続けます。
一方で、言海は「はく」に対する「履く」は認めていません。
一般にも「はく」は「穿く」と書かれていたので、この時代のものには「履物を穿く」という書き方が表れます。
しかし、「はきもの」が「履物」である以上、「はく」も合わせて「履く」としたくなるところです。
そのことが、その後の「履く」の復権に至ったのかもしれません。
用例
ここで現代に戻って、少納言というサイトを使って、最近の書籍等での使われ方を見てみます*9。
靴をは(く等) : 221件
靴を履 : 150件
靴を穿 : 6件
靴下をは: 25件
靴下を履: 9件
靴下を穿: 5件
ズボンをは: 85件
ズボンを履: 8件
ズボンを穿: 18件
現状としては、靴・靴下を「はく」の漢字表記としては「履く」が優勢です。
ズボンは、漢字については「穿く」が優勢です。
しかし、「穿く」が当用・常用漢字表外になるズボンだけでなく、靴・靴下についても優勢なのは平仮名でした。
今後
今後、「はく」の表記はどうなるんでしょうか。
個人的には、「腰から下につける」という意味の「はく」にひとつの表記があったほうが日本語として便利だと思います。
明治から戦前にかけては、すべて「穿く」が使えたところです。
でも、「穿く」が支配しかけていたところに江戸からの「履く」が復権して侵食してきたという流れを考えると、今後統一される望みはなさそうです。
ネットで見る実態としては、「履く」はズボン・スカート類にもだいぶ進出しています。
直近では、(下品で申し訳ないですが)「トランクス女子を流行らせよう(提案)」のブコメ*10を見ても、本文では「穿く」が使われているのに、ブコメでは本文の引用以外では「穿く」は1個しかなく、それに対し「履く」は10個もあります。
しかし、ズボン・スカート類については「穿く」と「ちゃんと」書くことにプライドを持っている人はすでに多くいます。
それに、今後ツイッターなどで「正しい日本語」が拡散されやすくなるにつれ、「ズボン・スカートは『穿く』だ」という「知識」はいわゆる情報強者層にはどんどん広がっていくでしょう。
「はく」と平仮名で書くというのはこれまで多く行われてきたことなのですが、上のブコメを見てもわかるように、ネットでは平仮名表記はだいぶ少なくなっています。
そうすると、ズボン・スカートを「はく」というのも「履く」か「穿く」のどちらかになるのですが、前者は間違っていると思われ、後者は目に慣れないというジレンマがあります。
まあ、ズボン・スカートは最終的には「穿く」に収束するのでしょうが、せめて靴下類は「履く」に落ち着いてくれるといいなぁと思っています。
「靴下について『履』を使うのはおかしい」と言うなら、「靴をはく」に「履」を使うのもおかしいんですよね。
どうやっても妥協の産物になるので、どうせなら靴・靴下がひとまとまりのほうがいいんじゃないでしょうか。
(そうするとストッキングはどうなるという話になるのですが、まあ答えが出る問題ではないですね)
「はく」はひとつ
今さらですが、日本語の「はく」はひとつの単語だという当たり前の事実を確認しておきます。
「はく」という単語の意味は、言海の時代の「腰ヨリ下部ニ着ク」から変わっていません。
それをどう書くかが揺れているだけです。
しかし、あきれたことに、世の中には「はく」が二つの単語だと思っている人もいるようです。
高島俊男先生の言う、「健全な日本人」でない人ですね。
上に、日本人ならだれでもわかるように「とる」の意味は一つだ、と言ったが、「健全な日本人なら」と限定をつけたほうがよいかもしれぬ。漢字かぶれの日本人のなかには、「とる」の意味は一つではない、どの漢字を書くかによっていくつもの意味がある、別の語になる、と思っている者もいるかもしれないから。
今回、いろいろ辞書を調べるなかで一番あきれたのが「明鏡国語辞典第二版」です。
「穿く」の項目に、書くに事欠いてこんなことを書いています。
「履(は)く」と同語源。
同語源ってことは、今は別語ってことですか。
頭おかしいんじゃないですかね。
同語源の別語というのは、「読む」と「詠む」のようなものについては言えるでしょう。
「読む」と「詠む」は同語源ですが、現代語では別の単語なので、たとえば「彼は和歌を一首と本を一冊よんだ」とは言えません。*11
これを書いたのは何人か知りませんが、「ズボンと靴下をはく」とか「靴下と靴をはく」とか言わないんでしょうか。
まあ、実際はそこまで考えていないんでしょう。
漢字にくらまされて日本語が見えなくなっている
というやつですね。
嘆かわしいこと限りないですが、今後はこういう辞書が増えていくのかもしれません。
日本語のつながり
今では、「履く」と「穿く」を「ちゃんと」書き分けられるかどうかというのは、物を書く人間を判断するリトマス紙のようになってしまっているところがあります。
それはいいのですが、それに「漢字の意味」のような余計な解説を付け加える人も多くいるようで気になります。
この書き分けは歴史的経緯によるもので、「日本語の漢文からの脱却」の象徴的なひとつの例とも言えるようなものです。
「『靴をはく』は『履く』であって『穿く』ではない」というのも、時代が時代であれば、何をバカなことを言っているんだと漢学者にあきれられるところです。
「漢文は日本語の規範ではない」ということを前提に、この書き分けは成り立っています。
たまに、戦前の日本語を理想化して、戦後はその「古き良き日本語」から断絶してしまったように思ってる人がいます。
しかし、「漢文からの脱却」という流れで見ると、明治から戦前・戦後の日本語は一貫してつながっています。
「はく」について言うと、「はきもの」の表記として言海に「履」ではなく「履物」が採用され、大正〜昭和初期の国語辞典に「履く」が収録され、戦後の国語辞典で「穿く」から靴類の用例が削られるという、いくつもの段階を経て現状に至っているわけです。
最近「漢文脈と近代日本」という本を読みました。
そこから一節を引用します。
…私たちが立っているのは、漢文脈の秩序の外側に開拓された領野だからであり、それは、漢文脈的でないものを目指して開拓されたはずだからです。極端に言えば、漢文脈とは、いったんは捨てたはずのものです。そうであるならば、なぜ捨てたのか、それを捨てた私たちとは何であったのか、目を向けないわけにはいきません。
漢字クイズのようなものにゼロイチの答えを求めるよりも、こういう「日本語の来し方行く末」のようなことについて考えるということも、たまにはいいんじゃないでしょうか。
darts-clone の Java 移植
矢田さんのdarts-cloneをJavaに単純に移植したので、GitHubに上げました。
https://github.com/hiroshi-manabe/darts-clone-java
darts-clone については、矢田さんの日記に詳しい解説があります。
これを移植したときは、仕事で使えるかと思ってやってみたのですが、結局そのときは容量の小ささを重視して takawitter さんのtrie4jを改造して使うことになりました。
せっかくなので置いておきます。
これはいろいろな事情があり、かなり Java 的でないものになっています。
その背景には、上記の trie4j の存在もあります。
trie4j はダブル配列も含むため、通常であればそちらを使うのが簡単でいいと思いますが、darts-clone はいろいろと変態的な工夫(1ノードあたり 4 バイトしか消費しないとか、値が同じであれば DAWG という仕組みでかなり容量が節約できるとか)があるので、そういうのを求める場合に使うのがいいと思います。
darts-clone-java では、キーは byte で渡すようにしています。
移植元の darts-clone では、テンプレートでキーの文字型を指定できるようになっているのですが、あいにく Java のジェネリクスでは基本型は使えないので、byte か String(UTF-16)かを選ぶ必要がありました。
しかし、darts-clone を UTF-16 で使っても「辞書サイズは大きくなるし,構築時間は長くなるし,隙間だらけだしと良いところが見つかりません」ということになるので(矢田さんの日記より)、byte にしました。
最初、String のラッパーメソッドも用意して、内部で UTF-8 に変換して処理することを考えていたのですが、結局やめました。
それにはいくつか理由があります。
まず、ビルド時にはキーをソートして与える必要があるのですが、このソート順が String と byte では違うものになります。
Java の String をソートするとき、Unicode のコードポイント順ではなく、UTF-16 の符号単位ベースでソートしているので、UTF-8 に変換したときのソート順と変わってしまいます。
これはわかりにくいので、最初から String は渡せないようにしました。
また、共通接頭辞検索のひとつの典型的な使い方は、長い文字列に対して開始位置をずらしながら何度も呼ぶというものです。
String のメソッドを用意してしまうと、長い文字列が何度も何度も UTF-8 に変換されるという悲劇が起こりかねません。
そのため、byte[] と開始位置のオフセットで検索するようにしました。
そもそも、darts-clone をわざわざ Java に移植するようなことがなければいいのですが…。
どうも Java では、いろいろな事情から C++ のライブラリを使うということをあまりせず(JNI というものはあるのですが)、何でも Java で済ませるということが多いようです。
これには、Java のパフォーマンスの高さがあると思います。
C のように Java を書くと、C に近いパフォーマンスが得られるので、それなら Java で書いたほうが扱いやすいということでしょうか。
しかし、darts-clone を Java に移植するにあたって、ネイティブ型のみをメンバに持つオーバーヘッドのないクラスというものが作れないため、結構面倒なことになりました。
C++ から JVM バイトコードにコンパイルできたら、Java からも扱いやすくていいと思うのですが。
trie を使うとき、速さ重視ならダブル配列、容量重視なら LOUDS を使うのが定番です。
上で挙げた trie4j は LOUDS も含んでいます。
ただ、現在のバージョンではキーと値を関連付ける方法がありません。
仕事では、速度はボトルネックになっていなかったので、上で書いたように結局 darts-clone-java は使わず、trie4j を改造して、キーとユニークな id を関連付けられるようにして使いました。
欲を言えば、marisa-trie(同じく矢田さんによる、LOUDS とパトリシアトライを組み合わせた実装)も Java に移植できればいいのですが、あまりにも複雑すぎて、手が出ませんでした。
ちなみに、あまり情報はないのですが、pinarell...@gmail.com さんによる marisa-javaという Java バインディングはあるようです。
TeX の発音
今さら、TeX の発音が話題になっているようです。
もう何度目だというぐらい目にしている気がするのですが、この問題は本質的にややこしいのでどうしようもないですね。
この問題について書かれているページのひとつとして、以下のものがあります。
これは非常に詳しく書かれていて、付け加えることなんてないようにも思えますが、ほかの言語の事情も含めて書いてみます。
まず、クヌース自身の書いていることから。
上記のページにある通り、彼は「TeXを知っている人は、TeXのχをxとは発音せず、ギリシャ語のchiのように発音する」と明確に書いています。
発音記号では [tex](「テッフ」のような音)となります。
この [tex] を正式発音と考えると話は簡単です。
いくつかの言語では、この正式発音をもとにして、それぞれの言語流の発音をしています。
ロシア語では、[te] の部分が少しなまって [tjex](「チェフ」のように聞こえる)と発音します*1。
ドイツ語では、e の後ろで [x] が変化して [ç] という発音になり、[teç](「テヒ」のように聞こえる)となります*2。
どちらも、[tex] をベースに変化した音です。
つまり、日本語では [tex] の日本語流発音をすればいいということになります。
日本語には [x] の音はないのですが、「バッハ」「ゴッホ」などではハ行の音になっています。
そうなると、[tex]も同じように「テッフ」とするのが筋ということになります。
ここで、「じゃあなんでクヌース自身は『テック』と言っているんだ」という話があります。
でも、実は話は簡単です。
[tex] の英語流発音が [tek] だからです。
TeX に限らず、英語では原音が [max] の「マッハ」も「マーク」のように発音されます。
そう考えると、ロシア語やドイツ語の場合と同じように、英語でも [tex] という正式発音をその言語流に読んでいるだけということになります。
こんなややこしいことになったのは、クヌースが英語にない発音を正式名称とした ということが原因です。
でも、そういうことは固有名詞ではよくあることです。
言語を置き換えて考えてみます。
たとえば、日本語のアニメで「ヴィンセント」というキャラクターが出てきたとします。
そうすると、作品中ではこれは [binsento] のように読まれることになります。
でも、作者の頭の中では [vinsent] のような英語発音が想定されているはずです。
さて、この「ヴィンセント」を諸外国語に訳すときに、"binsento" をベースにするのがいいか、"vinsent" をベースにするのがいいか。
まあ、普通に考えたら後者ですよね。
「作者のその言語での発音」よりも、「作者の脳内発音」を重視するわけです。
TeX の場合は、作者自身が脳内発音を明確に書いているので、なおさらそちらを基準にするのがいいように思えます。
でも実際には、アメリカでみんな「テック」と言っているということには無視できないほどの影響力があります。
おアメリカ帰りの人たちなどは当然「テックが正しい」という意見にならざるを得ないわけです。
これは言ってみると、アメリカ人の日本アニメオタクが、「ヴィンセント」というキャラの発音について「Vincent じゃねーし! Binsento だし! 日本人みんな Binsento って言ってるし!」と言うようなものだと思うのですが。
さらにめんどくさいことを言うと、日本でよく聞く「テフ」という発音は全然 [tex] に近くない ということもあります。
「バッハ」や「ゴッホ」などのように語頭にアクセントがある場合はまだいいのですが、「テフ」の場合はいわゆる専門家アクセントで、「フ」のほうが高く読まれます。
そうすると、「フ」の母音がはっきり目立って、元の [tex] には似ても似つかない印象の音(少なくとも、私はそう感じます)になります。
原理主義的に考えると、「テッフ」(語頭にアクセント)と読むべきということになってしまいます。
結局、クヌースの脳内発音を重視するか、クヌースの実際の発音を重視するかという問題になるので、「これが正しい」という結論はありません。
・英語ではテックのように読まれる
・クヌースが意図した発音は [tex] で、それをもとにした発音をする言語は多くある(英語もそのひとつと解釈できる)
ということさえ押さえておけば、日本語では「テフ」と読んでも「テック」と読んでもいいんじゃないでしょうか。
何度も何度も繰り返されてきた話題なのでいい加減うんざりしている人も多いかもしれませんが、「テック派」へのカウンターとして一応書いてみました。
いい話(W社を辞めました)
(2015/09/01追記:この記事は私がW社に在籍した2013年4月から2014年4月までの間の個人的な経験に基づくものです。就職の参考にされる方は、その後W社の社風や開発者の扱いに変化があったかどうか等についてご自身で最新の情報を得ていただければと思います。)
(2019/08/17追記:社名を「W社」に置換しました。)
記事タイトルの通り、W社を退職したので、退職エントリを書く。
(最近雑文に対していろいろと予防線を張ることが流行っているらしいので、一応これもポエムだと書いておく。役に立つことは書いていない)
今日が最終出社日だった。
ちょうど 1 年ぐらい勤めたことになる。
2 社連続で 1 年で辞めたことで、自分が社会不適合者であることが誰の目にも明らかになってしまった。
これから先の人生の見通しは暗い。
その間に子供が生まれたのだが、不憫でたまらない。
いい話というのは、Google を辞めたりして調子に乗っていた*1ろくに技術力もない人間が、落ち着くべき末路に落ち着いたという意味でのこと。
(Googleに勤めていたことを書くと過去の栄光にすがる情けない人になるので普段は書かないが、今回は転落人生というコンテンツ性のために書く)
仕事
W社というのは、よく知られているウェブサービスの会社。
ぼくは就活力がゼロなので、ツイッターで募集しているのを見て、それで受けて決めてしまった。
W社では、いくつかのプロダクトに関わった。
どれも、それによって誰かの利便性を上げられると感じられるという意味でやりがいがあった。
少なくとも、自分の信条に反するものを作っているということはなかった。
W社に応募したときは、「自分には自然言語の関わる仕事しかできない」という思い込みがあったけど、結果的に自然言語処理とまったく無関係の仕事でそれなりに成果が出せたので、そういう意味では今後の就職活動で自信が持てるようになったと思う。
人間関係
ここからが本題。
W社の開発グループは数人しかいないのだが、先輩が「実質上司」としての役割を果たしていた。*2
実質上司のひとりは威圧的で、彼の好み(彼の中での宇宙の真理)に外れる書き方をすると、コードレビューで直すように言われた。
プログラマ以外にはわからないかもしれないが、屈辱だった。
たとえば、キャプチャしない正規表現について、(?:) ではなく () と書くように言われたことがある。
それは、ぼくにとって(数多くある)辞めた理由のひとつだ。
長いけれど、ぼくの日記から引用する。
ぼくは、キャプチャしない正規表現を (?:) でなくただの () で書くようレビューで高圧的に言われたとき、今の職場を辞めることを決意した。(まだ辞められていないのは純粋にぼくが無能なせいだ)
キャプチャしない正規表現を () で書くこと自体は、そこまでの悪じゃない。
ぼくも昔はそう書いていたし、(?:) を知ってからも使い続けていたし、今でもワンライナーならそう書くかもしれない。
しかし、そう書くことを強制されるというのは、まったくの別問題だ。
それは人間としての尊厳に関わることだ。
「() で書いたほうがシンプルで読みやすい」と言われたら、確かに理がないわけではない。
でも、そのトレードオフで、そのいわゆる「読みやすさ」を重視することを選ぶ根拠、それを押し付けられる根拠は何だ? ということを突き詰めたら、相手のほうが「偉い」という「権力」しかない。
権力で押さえつけられるというのは、奴隷の立場であるというのと同じことだ。
子供がいなかったら、その日のうちに辞めているところだ。
いくら貧乏で、辞めたら餓死する状況でも、隷属してまで生きる価値のある人生なんてあるものか。
(もちろん、正規表現の件はひとつの例にすぎない)
人間性もひどかった。
隣の席の同僚が実質上司のコードレビューをしたとき、少しプログラムの構造に関わることを指摘したといって、誰が見てもわかるぐらい感情的になって怒っていた。
普段、自分基準で異常に細かいコードレビューをしていることを完全に棚に上げて。
また、別の実質上司は、何よりも「100 % の安全」を重視する性格だった。
MIT ライセンスの JavaScript 外部ライブラリを使おうとすると、「使っても問題ないか調査してください」と言われ、またできれば外部のものは使わずに実装してほしいと言われた。
そんなよくわからないものを使って訴えられて大変なことになったらどうするんだ、という雰囲気だった。
そのときのツイートがこれ。
ところで、会社には実質上司よりも偉い創業メンバーたち(以下「偉い人」とする)がいる。
ライセンスの件は、偉い人が問題ないと決めてくれたおかげでなんとかなった。
何をするにも、実質上司たちの頭越しに偉い人たちと話をしないと、バランスの取れた行動ができない。
幸い、偉い人たちは話の通じる人たちだったので、その点ではよかったのだが。
一番クソだと思ったのは、偉い人たちからプロジェクトを引き継いだときのこと。
偉い人たちはベンチャー気質が残っているので、効率と安全というバランスはかなり効率寄りだった(要するに、多少いい加減だということ)。
で、引き継いだぼくが同じやり方でやろうとすると、実質上司たちにボロクソに叩かれる。
そこでぼくが思ったのは、次の二つ。
1. 偉い人たちがやっていたやり方が会社にとってよくないと思っていたんだったら、偉い人たちに対しても諫言するべきだったんじゃないのか?
2. バランスを効率側に倒して会社にとってよくないことになったとしても、その影響を一番受けるのは偉い人たちなのに、実質上司たちは何の権限があって彼らと違うバランス感覚で判断をしているんだ?
もちろん、わかってみると理由は簡単だ。
彼らにとって、意見を言うことは「逆らう」ことなので、彼らよりも「上位」の存在のやり方に意見を言うなんて論外だけど、自分よりも「下位」の存在に対しては自分たちが支配できるということだ。
長い間ヒトとして生きることができていたぼくは、すっかりそういうサル的行動については忘れていた。
まあ、ぼくがこれまで運がよかっただけなんだろう。
人間にそういう面があるということは、ぼくだって聞いて知っていた。
ただ、ぼくが最初に勤めた会社も、二番目に勤めた Google も、そんな権力関係みたいなものとは縁のない世界だったから、あまり実感がなかったというだけだ。
あまりにも保守的なため、新しいものが何も使えない。
雰囲気がギスギスしているので、改善の提案もなかなかできない。
間違えたら元に戻すのが大変だという理由で、プログラミングにもいろいろな制約があった。
息が詰まりそうだった。
もちろん、愚痴を言うだけではしかたがないので、ぼくもいろいろ行動した。
指さし確認的・精神論的な「安全性」から脱却するために、多少なりともテストの自動化をしたり、先進的なバージョン管理システムの導入を推進したりした。
最終的には、前よりもずっと変更を加えやすい状況にすることができた。
でも、それらはもちろん、偉い人や同僚の助けを借りてやらなければいけなかった。
健全さやバランスを志向する精神性が実質上司たちにはないので、ぼくひとりでは何もできない。
政治的にやることはできたし、実際に少しはやったわけだけど、空しかった。
何をどう変えようとしても、また変えても、根本的な「文化」が変わらない、また変えられそうな見込みもない。
人間関係について、飲み会で偉い人のひとりと話をしたこともある。
すると、「人が辞めることによって人間関係が変わることもあるし、固定的ではない」と。
冗談じゃない。
実質上司たちは、辞めるどころか周囲を辞めさせる側じゃないか。
W社にいたことで、ぼくはそれまでプログラマとして当たり前だと思っていたいろいろなことの大切さを再確認できた。
技術的な健全さを目指す長期的な方向性。
健全な方向性を実現するための好奇心・向上心。
好奇心・向上心を保証するための余裕。
人として対等な、信頼のある人間関係。
でも、実質上司たちが間違っているかというと、必ずしもそうではないのかもしれない。
W社のサービスはすでに完成されていて、何よりも大事なのは「今あるものを変えない」という銀行的発想なのかもしれない。
そう考えると、間違っていたのはマッチングということになる。
(実質上司たちとは面接で会わなかったので、マッチングに必要な情報を得ることができなかったのは今でも残念だ)
興味
偉い人との話では、技術力のある会社の話題になったこともある。
レシピサイトやイラストサイトなど。
そのとき、「じゃあ、そういう会社に行きたいと思う?」と聞かれた。
それに対してぼくは、「いや、料理もイラストも好きじゃないので」と答えた。
すると、大笑いされた。
そういうことじゃないだろう、と。
ぼくは、何が「そういうことじゃない」のかわからなかった。
料理にまったく興味のないぼくは、ネット上のレシピがすべて消え去ったとしても何とも思わない。
そんな人間が、レシピサイトで働けるというのか?
ぼくは、言語に興味があるから、少しでもそれに関わる仕事がしたいと思ってW社を選んだ。
でもそれは、工場で働くライン工が最終製品が何であるかを気にするような、馬鹿げたことだったんだろう。
最初、ぼくの問題はたまたま悪い実質上司に当たったというだけだと思っていた。
しかし、その後も偉い人との会話を続けることで、根本にある問題に気がついた。
偉い人レベルでの、従業員は使い捨て可能・交換可能な部品であるという見方。
(こういうことを書くと、シニカルな人は「会社とはそういうものだ」と言うだろうが、これまで勤めた2社ではそういうことはなかった)
努力
「お前がそんな境遇になったのは技術力がないからだろう」と言われるかもしれない。
確かに、努力でひどい環境から抜け出した人のサクセスストーリーはある。
ぼくが泥沼で苦しんだのは、実力不足という要因もあるだろう。
それでも、ぼくはマイペースに努力はしている。
能力の範囲内で成長はしているはずだ。
それはトップレベルの人から見たら、目に見えないぐらい微々たるものかもしれないけれど。
人生は長いから、限界以上に頑張ってもすぐに息切れしてしまう。
遠くを走っている人には、「俺は『走る』というすばらしいアイデアを思いついたのに、お前は何で歩いてるんだ?」と言われたりもするけれど、自分は自分のペースで歩き続けるしかない。
書くことについて
「プログラマは黙ってコード書けよ」みたいな考え方がある。
だが、ぼくはそういう言説とは全力で戦っていく。
確かに、努力をあきらめてのらりくらりと生きているようなプログラマもいるのかもしれないが、能力の範囲内で精一杯頑張って、それでももがいているプログラマも数え切れないほどいる。
人間の生まれ持った能力は違うし、抱えているハンディキャップも違う。
運良くパラメータと環境が揃った人間だけが勝ち組になれるなんて、いくらかっこつけたところで、原始時代と同じじゃないか。
プログラマがものを考えないでいると、ごく一部のトップ以外は、会社に交換可能な部品と見られて底辺を這いずることになる。
ぼくはそれをこの会社で実感した。
「もっとひどい環境で苦しんでいるプログラマはいくらでもいる」と思う人はいるだろうし、それは事実だと思う。
でも、そういう人たちは何かを書くエネルギーすらなかったり、会社のことがトラウマになって書けなかったりする。
だからこそ、まだ恵まれているほうのぼくが書いている。
下を見て安心したり、自分の環境を自虐ネタにしたり、そういうことはしたくない。
(ところで、この記事を見てW社の環境がいいと思った人はぜひ受けてほしい。正しいマッチングを促進することになると思う)
流動性
辞める理由は、ぼくが人格的にダメでストレス耐性が低いというのもあるけど、「流動性を高めたい」というのもある。
人材流動性が高まることで、それぞれの組織には適した人材が残るようになる。
「人間を部品として見ている」会社、「変化を嫌う」「好奇心がない」「製品に対する関心がない」といった文化がある環境では、それに合う人が残っていく。
もし、それらの特徴を備えた会社が生き残る方向に市場の力が働くなら、それはしょうがない。
でも、ぼくはソフトウェア開発というのはそういうものじゃないと思っている。
自分が機械にならなくても、好奇心を持って果敢にチャレンジすることで生産性や信頼性を上げることができるのが、プログラマという職業なんじゃないだろうか?
トップレベルの人材でない限り、健全さ・好奇心・向上心・余裕・人間としての尊厳といったものは贅沢品にすぎないんだろうか。
ぼくはそうは思わない。
現時点では、そういうものが持てる健全な会社はごく一部で、トップレベル人材の分の場所しかないかもしれない。
でも、その健全さは「頑張ったご褒美」として与えられているものではなく、それ自身が成長力につながっているはず。
だとしたら、そういう会社が勝つことによって、よりよい環境が増えていくんじゃないだろうか。
そのためには、プログラマの行動が必要だ。
プログラマが、人間として頭を使って考えること。
プログラマが、いる場所・いた場所の情報をオープンにしていくこと。
プログラマが、いるに値しない場所から勇気を持って去ること。
プログラマの環境を改善するには、これらが大事だと思っている。
少しずつでも下のレベルにまで健全さが波及するよう、市場の力が働いてほしい。
収入
収入について、在職中にプログラマの生産性と報酬という記事を書いたことがある。
そこに「年収 1000万円」という職場の例を出したけれど、それはただの仮想の話だ。
実際は普通レベルだった。
(正社員として普通に給料をもらえるという時点でものすごく贅沢なレベルの話なのはわかっているけれど、子供がいるのでしんどかった。今は、妻が働くために子供は妻の実家に預けている)
よかった探し
会社についてのいい面も書いておく。
何よりもよかったのは、社長の人間性。
常にポジティブで、明るく、エネルギーにあふれていて、ユーモアを忘れず、決断力もある。
まさに起業家に向いているタイプだった(ぼくとは正反対だ)。
また、同僚(×上司)にも恵まれた。
同僚は、わからないことを聞くと何でもすぐに教えてくれた。
「聞いたほうが早いことは聞く」という、合理的な文化があった。
そのほかによかったのは、定時退社と有給休暇取得が自由にできたということ。
毎日、18:00 の瞬間に帰っていたので、10分遅れると妻に心配されるほどだった。
(さすがにほかの人はそこまで早くはなかったが、それでも30分も残業しないぐらい)
さらに、会社には数多くの本があり、自由に借りることができたのも精神的によかった。
(金銭に換算すると大したことはないが、教養を重視しているという意味で)
それに、Java や Web プログラミングを取り巻くエコシステムについて、ある程度の知識を得られたのもよかった。
一年前のぼくは、Java にも詳しくなかったし、Java の周辺技術も何ひとつ知らなかった。
個別プログラミング言語の経験でなく、ポテンシャルによって採用してもらえたということではありがたく思っている。
また、会社の偉い人たちはすべてにわたって合理的で、話が通じやすくてよかった。
ぼくが Google を辞めたときのブログも読んでくれていて、そのうえで採用してくれた。
W社を辞めるときにブログを書くことも想定内で、そのうえでメリットのほうが大きいと判断してくれたんだと思う。
実際、それなりの成果は上げられたはずだと思っている。
この先
さて、最初に書いたように、今後の人生の見通しは暗い。
でも、転落人生というコンテンツとしてはいい感じだと思っている。
今後、もっと情けない境遇になることがあったら、それも報告したいと思う。
(万が一人生が好転した場合はコンテンツ性が低いので書かない)
以前 Google を辞めたことについては、今でも後悔していない。
というのは、ぼくはプログラマとして「再現性」を重視しているからだ。
もしぼくに実力があれば同じくらい環境のいいところにまた入れるだろうし、そうでなければ再現性のない幻にすぎない。
結果として後者だったわけだが、それならそんな幻にすがっていてもしかたがない。
この先、就職活動をするにあたって一番憂鬱なのが「権力」のことだ。
今後どこに行っても、権力という意味では常に一番下っぱになる。
これまで、そういうことを意識する環境にいたことがなかったので、そのことを気にしていなかった。
お気楽だったとしかいいようがない。
今後どこに行っても一番下っぱになるだろうし、権力闘争には向いていないのでそこから這い上がることもできないだろう。
そう考えると絶望的な気持ちになる。
Google を辞めたときは、開放感からケーキを買ってきてお祝いをしたぐらいだった。
でも、今回はとてもそんな気持ちにはなれなかった。
今日、家に帰って、晩ご飯を食べてから布団にもぐって、1時間以上ずっと泣いていた。
これまでのつらかった時間、失われた人生を思って、またこれからも底辺を這いずって生きることで失われる人生を思って。
希望
「ある場所でやっていけない人間は、ほかの場所でもやっていけない」というような話を好む人間もいる。
ぼくが学部で京都大学をやめて大阪外大に入ろうとしたとき、そういうことを言われた。
でも、実際に大阪外大に行ってみると人間も雰囲気も大違いで、ぼくはずっと幸せになることができた。
それ以来、そういう言説は信用していない。
人間の集まる場所は、一部の人が思うより、ずっと多様性に富んでいる。
ぼくも、一度だけそれなりに長く(5年)勤められた経験がある。
小さいところだったが、カリスマ的な社長がいて、思いついたアイデアをいつも開発室に話しに来ていた。
社長の人柄もよく、ひとりひとりの従業員と人間として接していた。
その職場では、「権力」という単語が頭をよぎったことは一度もなかった。
いい環境だった。
(残念ながら、そこは社長が亡くなって以来、帰りたいと思えるような場所ではなくなってしまった)
だから、自分に合った場所に出会える確率もゼロではないはず。
いつかまた、そういう場所が見つけられるよう、青い鳥ハンターになっている。
辞めることを決めた週末、結婚記念日のお祝いとして石油王的娯楽(映画鑑賞)をした。
そのときに見た映画「それでも夜は明ける」は、19世紀のアメリカを舞台としたもの。
自由黒人だった主人公が南部に拉致されて 12 年間奴隷として暮らしたという実話に基づく映画だった。
それを見ながら、思わず自分の境遇と引き比べていた。
そして、自分の幸せに気づくことができた。
映画の主人公は、奴隷主や奴隷使いの当たり外れで環境がよくなったり悪くなったりするが、彼は主人を選ぶことができない。
でも、ぼくは少なくとも奴隷主を選ぶことができる。
逃げても、逃走奴隷としてリンチされることもない。
職業選択の自由はすばらしい。
人類がこれまで積み上げてきた概念の大切さを思い知った。
これからしばらく、隷属から離れて、人間として生きることができる。
次の職場が見つかるかどうか、見つかっても人間として生きることができるかどうかは、まだわからないけれど。
上で引用した日記の続き。
いつか仕事が辞められたら、今の職場にいた時期のカレンダーを真っ黒に塗りつぶして、失われた日々を追悼したい。
ぼくは今後、この期間のことをずっと供養していきたいと思っている。
そのためには、今後の人生をこの時期よりもいいものにしないといけない。
頑張ろう。