Go言語は、なんというか「ちょうどいい」言語だな、と思っている。異論は認める。
Go言語の登場時、なんせGoogleが大々的に発表した新しいプログラミング言語であるし、Rob PikeやKen Thompsonといった有名人の関わりもあり、華々しかった。そして、その登場を眺めたプログラミング言語マニアは、そのダサい仕様にわりとすぐがっかりして、興味をなくした。ということがあったと思う。今はGoはけっこう広く使われていて人気もあるけど、ここに至るまでには紆余曲折があった。
Go言語、なにせ2010年代にもなってなんせジェネリクスもない(そのわりにスライスや配列、ハッシュテーブルだけが標準にあり、特別扱いされている)。例外処理もない(これはまぁそのほうがいいだろうという人もいるだろうけど)。そこらじゅう if err != nil
だらけ。テストにアサーションもなく、ひたすら地道にif文を書くべしとされている。いくつかのビルトインな関数(たとえば make
など)は構文上も特別扱いされていて、直交性がかけらもない。
オブジェクト指向的なことはできるが、C++やJavaのようなクラス志向ではない。継承が言語仕様にない。interfaceによるduck typingはできる。メタプログラミング的なことはやりづらい。オブジェクトは動的なところが一切ない。なんかデザインしづらそうだな、というふうに思った。
というわけで、登場時は「なんだかぱっとしない」「かっこよさがない」といったイメージであったように思う。すくなくとも自分は。
Go言語の「ちょうどよさ」
結果的にはこういうマニア視点はまったくのお門違いだったといえるだろう。Go言語はおおいに流行っている。これをGoogleによるゴリ押しだという主張はきっとあるだろうけれど、それはたぶん違う……もちろん、会社の支援のもとで言語仕様の改善や標準ライブラリの拡充などの発展があって便利になっていったという側面はあるけど、それはまあ「ゴリ押し」とは言わないだろう。
Goの独特のニッチにうまくハマったのだと思う。それはたとえばWebサーバやRPCサーバ、ちょっとしたユーティリティツールやサービスにあたる。GCがあって、並列処理ができ、標準ライブラリだけでもけっこういろんなことができて(http2サーバでJSONを返したりとが簡単にかける)、単純だけど静的型付けで単純な間違いは防げる。Goのインタフェース志向なduck typingは使ってみるとわかりやすく簡単だったし、実装の継承があると便利な場面というのも別になかった。こういう用途には便利だった。
言語マニアが「ださい」と思ったところは、実用上はそんなに大きな問題になることが多くはなかった。多くのGoプログラマが証言するように、Goを書いていてジェネリクスが必要なのになくて困るという場面はほんとうに少ない。もちろんまったくゼロではないし、今後たぶんジェネリクス的な機能は入ることになるだろうから、それはそれでいいことなんだけど、でも、マニアの文句なんてそんなもんだという話でもある。標準組み込み型の特別扱いがわりとうまく機能してるとも言える。
Goコマンドの導入によりツールチェインはわかりやすく使いやすくなったし、ビルドも速く、シングルバイナリでデプロイや配布が単純というのもよかった。こういうところは言語マニアはあんまり評価対象としないと思うけれど(言語そのものというよりは処理系の話だし)、そこには大きな意味があったと思う。Goは性能がよいというイメージ(実際のところ、最速でないにしろスクリプト言語よりは十分速い)も普及に一役買ったことだろう。
Goはworse is betterか?
Goの「ちょうどよさ」というのはどういうものだろうか。先進的でかっこいい理論にもとづいた複雑な言語より、ダサいけど使いやすいのがいい、というのが端的な評価になるとおもう。これはworse is betterを思わせるところがある。ただ、読み直してみると、Goはworse is betterでいうところのNew Jerseyアプローチではないように思える。
Worse is betterの結論というのはこうだ。実装が簡単で使うのも苦じゃないようなものは、みんなが勝手に再実装しやすい。そういう再実装は完璧じゃないにしてもまあまあ使えて同じぐらい使いやすい。そうやってウィルスのように広がっていく。MITアプローチで作られるものは、ぜんぜん完成しないか、完成しても使い物にならないかで流行らない。
JSONはまさにworse is betterといえる。自作JSONパーサを作るのだってすごく大変じゃない(性能とかを気にしなければ)。コンパクトでミニマルである良さみたいなものがある。
でもGoはランタイムも大きくてけっこういろんなことをしてくれる言語だ。GCもある。goroutineはカーネルスレッドの複雑さを隠蔽してくれる。再実装はぜんぜん簡単じゃない(実際、Goの再実装なんてllvm-goとか数えるほどしかない)。GoはいろんなOS、アーキテクチャに移植されてるけど、これはどっちかというとエンジニアリングリソースの投入量によるところが大きそうだ。それにまた、Goは裏側で意外といろいろ複雑なことをしてくれることがある。Goは間口の広さと取っ付きの良さ、仕様のわかりやすさによって普及したが、そのわかりやすさ、単純さのためには実装の複雑さを引き受けている面がある。かといってMITアプローチともいいがたい。
これはたとえばTOMLのちょうどよさにも通じるところがあると思う。TOMLは書き手にはシンプルでいい言語なのだが、これまたnew jerseyスタイルではない。実際に再実装するのは意外と厄介。仕様は細かいところまでいろいろカバーされており、こういう場合はエラーになる、こういう場合はこうなる、といった仕様をすべて正しく実装するのはじゃっかん面倒くさい。そういうこまかい部分がありつつも、全体的には「なんとなく人間が書いてわかりやすいような挙動」が取られるようになっている。データ型も日付型とかがあったりしてミニマルな良さもない。
まあいまさらworse is betterでもないだろうという話でもないのかもしれない。あるいは、MITとNew Jerseyの相克は、「ちょうどよさ」の新しい相を生み出したのかもしれない。これが今の時代のちょうどいい表現なのかもね。言い過ぎな気もするけれど。