動的型付け・静的型付け論争への私見

2023/09/12に公開

プログラミング言語に関するこれがいいあれがいいという議論は半分くらい宗教戦争と化してよく白熱する。
その中でもう燃えあがる論争の一つが動的型付けと静的型付けの対立だ。

最近だと、とある有名OSSでTypeScriptをやめてJavaScriptに戻したことが大きな話題となった。

https://world.hey.com/dhh/turbo-8-is-dropping-typescript-70165c01

それに、乗っかって、Ruby開発者のMatz氏のツイートが掘り起こされたりした。

https://twitter.com/yukihiro_matz/status/113795262165680128

これらの方々に比べれば自分の実力・経験値は遠く及ばないとは思うが、たまにはと思いこの動的・静的型付けとプログラミングの生産性への自分の私見をまとめてみようと思う。
最初に断っておくと、これは自分の経験に基づく感想という側面が大きく、何か定量的・定性的な裏付けがあるものではないことを強調しておく。
日頃からRustのような強い静的型付け言語に関する発信をしていることからわかるように、自分は静的型付け言語を好んでいる人間であるということも断っておく。
また、上に挙げた個別の事象の詳細への批評をするものではない。特定個人やプログラミング言語を批判する意図もない。

静的型付けの有用性

動的型付けと静的型付けの論争はよく白熱するとは言ったが、自分はこの論争はほとんど終わったものだと思っている。
というのは、静的型付けの有用性はもはや誰もが認めているように思えるからだ。

例えばTypeScriptの流行はその一例だろう。もともと動的型付け言語であったJavaScriptに対して、静的型付けを導入したこの言語は今やWeb開発のデファクトスタンダードとなっている。
TypeScriptが流行する前は、もっと異なる文法でのAltJSとしていくつかの言語が出現したり、Flowという型ヒントをつけるなどにより型検証を行うツールが出現したりした。
(AltJSの一部は動的型付けのものもあったが)これらの試みで解決しようとした問題は、JavaScriptの動的型付けによる開発時の不安定さだったといえる。

JavaScript以外だとPythonの型ヒントの公式サポートがある。
ランタイムが直接検証するわけではないが、IDEや静的解析ツールが型ヒントを利用して開発時の検証を行うことができる。

さらに言えば、StackOverflowのサーベイで最も愛されているプログラミング言語の1位を取り続けているRustは、上記のものよりはるかに強力な制約課す型システムを備えている。
Rustの学習コストは高いと言われ、強い制約を課すにも関わらず1位を取り続けるほどの人気を得ていて、GoogleやAmazonなどの大企業でも採用されている。

これらの事例からもわかるように、静的型付けの有用性は広く認められていると言えると思う。
現状の問題点はこの静的型付けをどこまでまじめにやるかという点であると思う。

上に挙げた例での型検証というのは関数型言語のような強い静的型付けと比べると厳格性は低い。
例えばTypeScriptのany型はどんな型でも受け入れる型である。このany型をどこまで許容するかは未だに論争になる。
また、複雑な型を管理するのは開発者にとって負担になる場合もあるし、学習コストも高くなる。
型検証のためのツールを導入するのにもコストがかかる。

TypeScriptやPythonの型ヒントが受け入れられたのは、学習コストやツール導入のコストが多くの人にとって合理的な範囲であったからだと思う。
TypeScriptの文法はJavaScriptとほぼ同じであり、型も困ったら最悪anyにして誤魔化せば良い。トランスパイラの導入も結局レガシーブラウザ対応のために必要になるので、それと同じようなコストで導入できる。
Pythonの型ヒントも、あってもなくても動くので障害になることは少ないのではなかろうか。

Rustの場合はTypeScriptのanyのような抜け道は存在しないが、そのコストを上回る恩恵がある場面で採用されているのだろう。
例えばRust for Linuxでは、Linuxのカーネルの一部をRustで書き直すという試みが行われているが、Linuxカーネルにおいてはバグを防ぐことが重要であり、そこで強い静的型付けを備えている言語というのは魅力である。
Linuxのような低レイヤー領域ではランタイムが必要な動的型付け言語をそもそも採用することが難しいという事情もあるが、そういう事情のないWeb開発のような領域でもRustが採用される場合もある。

これらの例を見るに、静的型付けの有用性を否定する議論は時代遅れであり、論点があるとするならばそれをどれだけ厳格にやるかという点にあると思う。

なぜ静的型付けが有用なのか

静的型付けがなぜ必要とされているか、ということについても考えを述べておく。

静的検証としてバグを防ぐ

最初にあがるのは静的検証としての役割であろう。
関数の入出力や変数の型を明示し、それらを静的に検証することで実行前にバグを防ぐ、ある種の形式手法とも言える。
最近で言うと、Rustはライフタイム・所有権といった概念を型システムとして実装することで、メモリ安全性を静的に検証が可能になっている。

Rubyのような動的型付け言語では、実行時エラーを減らす試みとしてテストを書くことが多い。
特にユニットテストの文化やテスト駆動開発はRubyのような動的型付け言語の開発で盛り上がっていた記憶がある。
これらのテストは静的型検証がないデメリットを補うものであったという側面があったと思う。

静的型付けはこれらのテストを完全に置き換えるものではない。
そのため、Rustのような厳格な型を持つ言語でもユニットテストのためのフレームワークが標準で組み込まれている。
しかしながら、静的型付けによって検証される性質は限定的ではあるものの、厳格な検証となる。
テストと静的型付けを相補的に組み合わせることで、より安全なプログラムを書くことができる。

ドキュメントとしての役割

静的型付けはドキュメントとしての役割も果たす。
関数の入出力がわかれば、おおよそ関数の役割が推測でできるし、構造体のフィールドが型情報として明示されていれば、ほしい情報を得るにはどのフィールドを参照すれば良いかがわかる。
例えば外部のウェブサービスのAPIのラッパーをつくるとき、そのAPIを呼び出す場合のリクエストとレスポンスを型として定義すれば、そのAPIのドキュメントを読みに行く必要は少なくなる。
また、形式的に定義されているので、読み方も統一される。

IDEやコード解析ツールのサポート

静的型付けされた情報を用いることで、IDEやコード解析ツールの挙動をより正確なものにすることができる。
例えば、変数の型が確定していれば、その変数に対してどのようなメソッドが呼び出せるかは機械的に判定できるので、IDEの補完をより正確に絞り込むことができる。
また、プロジェクトをまたいだコード検索も、変数の型がわかれば同名の関数が異なるプロジェクトに存在していても機械的に区別して判定することができる。

なぜ論争は起きるのか

静的型付けの有用性を否定する議論は時代遅れであると述べたが、なぜ未だにこの手の論争が起きるかを考えてみる。
結局は静的型付けによって得られるメリット・デメリットをどう評価しているかに尽きるだろう。
そして、その評価は個人がどのようなツールを使っていたり、どのような立場で何を経験してきたかに依存する。

例えば、冒頭で紹介したMatz氏のツイートだが2011年のものであり、その当時のプログラミングにまつわる環境を考えると、そもそもTypeScriptだったりRustのような選択肢がない状況であった。
(Rustの開発開始は2006年ではあるが、現在のように言語仕様として実用的になってきたのは最近である)
そのような状況下だと、静的型付け言語としての選択はC++やJavaのような弱い型システムの言語か、OCamlやHaskellのような書き方が他のプログラミング言語とは大きく異なる関数型言語くらいしかなかった。
そのようなものを比較してしまうとRubyやPythonのような動的型付け言語のほうが生産的という結論も説得力があった。

また、IDEの選択肢も今はVSCodeやJetBrains製品があるが、当時はEclipseやVim・Emacsくらいしかなく、型情報から得られる恩恵も少なかった。
Eclipseは現代の他のIDE製品と比べると、動作も重く使い勝手が悪かった。
Vim・Emacsはプラグインを導入すればある程度できたものの、language server protocolもなかったので今ほどの開発体験は得られなかった。

さらにいうと、Matz氏や先ほどのTypeScriptをやめたというブログの著者であるDHH氏はベテランであり、そのプロジェクトのコア開発者であるという背景もあるのではないかと推測している。
先述した静的型付けのメリットの一つであるドキュメントとしての役割だが、コードを書いた張本人であるコア開発者にとっては、そのドキュメントの価値は相対的に低いくなる。
また、自分の書いてないライブラリ等を使うにしても、ベテランでもあり自分の知り尽くした言語やライブラリを使う上でドキュメントを参照したくなる場面というのは少なくなるであろう。

このように、立場や時代で静的型付けがもたらす恩恵が少なくなると、あえて静的型付けを導入するメリットは少なくなり、動的型付け言語を選択することが合理的になったということではないかと思う。

まとめ

静的型付けの有用性はプログラミング言語や周辺ツールの発展によって、静的型付けの生産性への寄与は大きくなり広く認められるようになった。
しかしながら、静的型付けをどこまで厳格にやるかという点については、立場や時代によって評価が変わる。
今後出現するフレームワークやツールによっては、静的型付けを厳格にやることのメリットが減少する可能性もある。

現状では積極的に静的型付けが可能な言語やツールを選択するのが良いと思うが、開発チームのスキルセットやプロジェクトの要求など検討した上で、静的型付けをどこまで厳格にやるか(あるいは完全に放棄するか)を決めるのが良いのではないかと思う。

Discussion