Go を褒め殺ししてみる

no extension

母国語としてのプログラム言語

以前紹介したのだが,結城浩さんの過去の連ツイ

プログラミング言語との付き合い方というのはいろいろあってですね。自分の母国語という言語はある。それから現在学んでいる最中の言語というのもある。そして、仕事用の言語やら、他の人とのコミュニケーション用言語というのもある。そのあたりは、自然言語とちょっと似ている。

ITな業界で仕事をしているひとというのは、だいたいそういう感じでプログラミング言語とつきあっていると思っている。たった一つしかプログラミング言語ができないという人は少なくて、二つくらいは読み書きできる。三つ四つくらいはなんとなく読むのはできる。五つ六つくらいは何のソースか言える。

という記述がある。

まぁ「仕事用の言語」や「コミュニケーション用言語」ってのは独りで選ぶものではないので今回は除外するとして,「母国語」というのは上手い比喩だ。 自然言語と同じで「母国語」として定着しているプログラミング言語があればロジックや制御への理解も速いし,他言語を習得する際にも有利になる。

でも最初から「◯◯言語を母国語として習得するぞ」とかいう人はいないだろう。 使い込んで手に馴染んでいって初めて「母国語」になり得る。 問題は「どの言語か」ではなく「手に馴染むまで使い込むほどの動機があるか」だと思う。

「これからプログラミングを始めるならどの言語にすればいいか」という問いは今の季節の風物詩みたいなものだが,この問いだけでは「始める」動機が見えないし,その人が既に「母国語」と言えるものを持っているか否かで話も変わってくる。

先日見かけた

という記事も似たような印象を受けたが,回答に挙がっている RustGo の比較はなかなか興味深く,また大いに共感した。 ただ,回答された方は Rust 寄りみたいなので,対抗して私は Go を褒め殺ししてみる(笑)

なお,あらかじめ予防線を張っておくと,私は言語オタクでも文房具オタクでもないし,その手の宗教論争に巻き込まれたくないので,異論反論(当然あると思うけど)には反応しないのであしからず。

(前説おわり)

はやく作って はやく改(なお)す1

昔は「はやく作る」というのはスクリプト言語の独壇場だった。 近年のバズワードだった「AI」技術において Python が大きな牽引力として機能しているのは Python が「はやく作る」ことに特化した言語であることも大きいだろう。

しかし Go がこの状況を変えていく。

Go はコンパイル言語には珍しく(と言っていいのか分からないが)「はやく作る」ことに特化した言語と言っていい。 「はやく作る」というのは事前学習量やコンパイル速度やコード記述量を指しているのではなく「考えたことをそのまま書いて安全に組めるか」ということだ。 Go の言語仕様に組み込まれた簡便さも制約もこの目的のためにあると言ってよい。

たとえば Go は Java などの伝統的オブジェクト指向プログラミング言語とよく比較されるが,例外処理や継承など「考えたことをそのまま書く」ことにおいてノイズにしかならないギミックをあっさり捨て去っている。 Goroutine 間に優先順位が存在しないのも sync.Mutex が再入不可なのもちゃんと理由があるのだ(Generics は結局組み込むみたいだけどw)。

ちなみに「はやく作る」ことは「雑に作る」ことではない。 近年の流行語である「技術的負債」の本来の意図は「はやく作る」ことと引き換えにしているものを金融用語の「負債」に喩えたことだそうだ。つまり技術的負債の「返済」とは,システムやプログラムを「直す」ことではなく「改(なお)す」つまりリファクタリングを指している。

もうひとつの Go の特徴は,このリファクタリングに厚い言語であるということだ。 シンプルな言語仕様故に手を入れやすいし, interface 型による「構造型の部分型付け(structural subtyping)」によってオブジェクト間の関係を「疎」にできるため,再利用性の高い機能を別パッケージとして切り離したり,なんなら「出来のよくないパッケージを丸ごと入れ替える」なんてことも比較的容易だったりする。

一言で言うなら「はやく作って はやく改せる」のが Go 最大のメリットである。 道具に耽溺するのでなく振り回されるのでなく,自らのアイデアを「いい感じ」に実装する手段としてプログラミング言語を求めるのなら Go を選択するのは悪くない,と言っておこう。

「文」の制約

Go の言語仕様を読むところまで慣れた方なら気づいてると思うけど, Go は文(statement)の制約が強い言語である。 文の制約を強くすることで全体の言語仕様をシンプルにしている,とも言えるが。

たとえば if, switch, for といった制御文や = などの代入文は式(expression)として評価できないため,式の一部または全部として組み込めない。 分かりやすい例としては C/C++ などでは悪名高いインクリメント2x++” は代入構文のバリエーションとして評価されるため,式の一部として組み込めない,とかいったことがある。

y := ary[x++] // syntax error

あるいはもっと簡単に

a = b = c = 1 // syntax error

とかも無理。

こういった制約は,特に関数型プログラミング言語から来た人には大きな不満となるだろう。 この理由で Go に馴染めないというのであれば Rust のほうをお勧めする(笑)

富豪的プログラミングの代償

並列処理とメモリ管理はどんな言語でも悩ましい問題である。 特に両者が組み合わさると非常に厄介と言える。

たとえばスクリプト言語や Virtual Machine 上の動作を前提とした処理系ではスクリプト・エンジンや VM が並列処理やメモリ管理の厄介な部分を引き受けてくれるが, Go ではこれらを実行モジュールに組み込むことで高いパフォーマンス(とシングル・バイナリでのデプロイ)を可能としている。

富豪的プログラミングの観点からは,これらの仕組みはプログラマに有利に働く。 最初の節で紹介した Q&A の回答でも

言語仕様が小さくて、コンパイルがとても速く、GC (Garbage Collector)を採用してメモリ管理の煩わしさをなくすとともに、並列実行を容易にしています。

その分、単体での実行速度については妥協していますが、速度を求めるのなら処理を並列化しつつマシン側(実行環境)を増強すれば良い、というクラウド時代の解決策をとっています。つまり、コードのちまちまとした最適化で悩んでいる暇があるなら札束で殴ってさっさと解決しろ、ということですね。とても効率的な考え方です。

と解説されている。まさに富豪的(笑)

しかし,これと引き換えに「小さなシステム」に対しては無視できない代償を支払っている。 これは並列処理やメモリ管理を実行バイナリに埋め込むために POSIX への依存度が高くなっているためだ。

小さなシステムやシビアなリアルタイム処理3 には Go は向かないだろう。ましてやデバイスドライバや pure Go な OS カーネルなど夢のまた夢である。 そういうものに興味があるのであれば Rust のほうがお勧めだ。

なお,個人的に興味を持っている TinyGo なら LLVM ベースの小さいバイナリを生成することができる。組み込み用途であればこういった選択肢はありだと思う。

本当は WebAssembly に興味があるのだが,少なくとも Go 側が WASI (WebAssembly System Interface) をサポートしてくれないと無理かなぁ。

ブックマーク

参考図書

photo
プログラミング言語Go
アラン・ドノバン (著), ブライアン・カーニハン (著), 柴田芳樹 (著)
丸善出版 2016-06-20 (Release 2021-05-21)
Kindle版
B094PRR7PZ (ASIN)
評価     

Kindle 版出た! 一部内容が古びてしまったが,この本は Go 言語の教科書と言ってもいいだろう。感想はこちら

reviewed by Spiegel on 2021-05-22 (powered by PA-APIv5)

photo
プログラミングRust
Jim Blandy (著), Jason Orendorff (著), 中田 秀基 (翻訳)
オライリージャパン 2018-08-10
単行本(ソフトカバー)
4873118557 (ASIN), 9784873118550 (EAN), 4873118557 (ISBN)
評価     

Eブック版あり。公式ドキュメントよりも系統的に書かれているので痒いところに手が届く感じ。ただし量が多いので,一度斜め読みしたらあとは傍らに置いて必要に応じてつまみ食いしていくのがいいだろう。

reviewed by Spiegel on 2020-03-08 (powered by PA-APIv5)

photo
Effective Java 第3版
Joshua Bloch (著), 柴田 芳樹 (翻訳)
丸善出版 2018-10-30
単行本(ソフトカバー)
4621303252 (ASIN), 9784621303252 (EAN), 4621303252 (ISBN)
評価     

再勉強中。 Kindle 版のほうがちょっと安いが,勤務先でも使いたかったので紙の本にした。

reviewed by Spiegel on 2021-03-17 (powered by PA-APIv5)


  1. 「改す」を「なおす」と読むのは辞書的に正しい日本語ではありません。念のため(笑) ↩︎

  2. C/C++ ではインクリメント/デクリメント演算子は前置(++x)と後置(x++)があって機能が異なる。これに起因する不具合も多く,コーディング・ルールで「インクリメント/デクリメントの後置は禁止」とするところが多いらしい。 ↩︎

  3. ここでいうリアルタイム処理とは「分割されたジョブを決められたタイミングで決められた期間内に完了すること」を指す。 ↩︎