可変変数に対するJohn Carmackの見解
(twitter.com/id_aa_carmack)- John Carmack が 可変変数(mutable variable) の使用に関する個人的な見解を共有
- Pythonを使ううちに「単一代入(single assignment)」の原則をおろそかにしがちになったとして、自分自身で警戒する必要があると言及
- ループ内の反復計算を除いては、変数の再代入や更新を避けるべきだと強調
- 中間計算の段階がすべて残っていれば デバッグ時に役立ち、コードブロックを移動する際に 意図せず以前の値が使われる問題を防げる
- C/C++では、ほぼすべての変数を初期化時点でconstとして宣言するのが良い習慣だと説明
- 最後に「mutableがキーワードであってほしい」と述べ、不変性がデフォルトになることを望むと強調
1件のコメント
Hacker Newsの意見
Clojureを2年間使った結果、不変性がもたらす明快さを他の開発者に説明するのは本当に難しいと感じた
状態変化によって効果を生み出す考え方に慣れた人は、実際に体験してみるまで理解しにくい
たとえば
x = 7; x = x + 3; x = x / 2のように書くと、順序を入れ替えてもエラーにはならないが結果は変わる一方で
x1、x2のように新しい変数を使えば、順序が誤っている場合にエラーが発生して問題が明確になる結局、単一代入(single assignment)はこうした依存関係を明示的に表現する方法だ
関数型言語を使ったことのない同僚に、関数中心の考え方がどれほどテストしやすく、すっきりしているかを説明しても、なかなか伝わらなかった
Pythonは関数型スタイルを読みやすく書きにくく、JSのほうがむしろ良いと感じる
結局、好奇心の強い開発者だけがClojureのような言語を試すことになる
関数は外部状態を知らなくてよく、外部も関数内部を知らなくてよい
プログラム全体の状態を知らなくても、特定の関数だけを独立してテストしたりデバッグしたりできる
Haskellコミュニティが最終的には型システムの中で可変性を再発明しようとしているのを見ると興味深い
核心は副作用を最小限のコストで制御することだ
Haskellは型システムのせいで参入障壁が高く、F#はあまりに妥協的で、結局C#構文でコーディングすることになる
Clojureのhomoiconicityと強力なデータ構造のおかげで、「値として働く」という概念が初めてはっきり腑に落ちた
仕事で使うことはないだろうが、関数型言語やLispの経験がない人にはぜひ勧めたい
変数は基本的に不変で、すべてが式(expression)であってほしい
だが現実には、Clojure開発者としてPythonの侵攻に苦しめられている
今はTypeScriptの侵攻に苦しんでいるので共感できる
このやり方は変更のスコープを制限するのに本当に役立つ
言語間の部族戦争に巻き込まれる必要はない
生産性向上の時代には境界は無意味だ
Don’t Call Yourself a Programmer という記事を勧める
変数の再代入は最小限にしようとしているが、しばしば変数シャドーイングを使う
result = result.process()のようなパターンは簡潔なので好んでいるたとえば
process()が検証関数なら、どの時点で処理された値なのか不明確になりうるしたがって名前によって状態を明確に区別したほうがよい
例:
result = x |> foo |> bar |> bazまたは(-> x foo bar baz)result.process()って、いったいどのresultで、どのprocessなんだ?」後でコードを読む人は混乱する
「変数(variable)」という用語そのものがいつも引っかかる
不変なのに、なぜ variable と呼ぶのか?
Rustでは
mutを明示して初めて変更可能になる一方Cでは定数を作るのにプリプロセッサを使う必要があり、混乱を招く
xは呼び出しごとに異なる値を受け取るので、それ自体が変わる値だ再代入がなくても変数と呼べる
プログラミングはこの概念をそのまま持ち込んでいる
定数(constant)はすべての実行で同じ値を持つ
Variable (mathematics) を参照
IDEが変数の変更有無を視覚的に表示してくれるといい
たとえば、変更された変数を少しだけ目立たせるような形で
できるだけ
finalを多く使うと、コードは読みやすく保守しやすいIDEが警告を出し、本当に必要な場合だけ変更を許可するのがよい
Rich Hickeyのset vs listの話のように、意味を明確に表現する構造を選ぶべきだ
以前、スレッドセーフ性のために不変性を厳格に適用したプロジェクトに関わったことがある
そのおかげでコードは読みやすくなり、何が変わりうるのか追跡しやすくなった
それ以来、不変性の熱烈なファンになった
大規模なHaskellコードベースで働いた後にCへ戻ると、不変性がデフォルトであってほしいと思う
constでは足りない変更するにはポインタを使う必要があり、C++では関数呼び出しだけでも引数を変えられるので不透明だ
「ほとんどすべての変数を const で宣言するのがよい」という意見に共感する
Rustに言及すべきだろう
不変がデフォルトで、特定のブロック内でだけmutableを許可する構文を想像してみる
たとえばPythonの
withブロックのようにブロックを抜けると再び不変に戻るイメージだ
Rustのborrow checkerを見ると、この概念がどれほど複雑かわかる
「State is the enemy」という言葉がある
状態が増えるほど、テストすべき条件は指数関数的に増えていく
不変性はこうした状態爆発を防ぐ方法だ
Separation of Church and State