KotlinでいつものBrainF**kインタプリタを書いてみた件(+学んだ本が良かった件)
以前から話には聞いていたものの、
最近「ことりんはいいぞ・・・!」という話を聞く機会があったので、
試しに本を読んでみたわけです
- 作者: Josh Skeen,David Greenhalgh,吉川邦夫
- 出版社/メーカー: 翔泳社
- 発売日: 2019/02/14
- メディア: 単行本(ソフトカバー)
- この商品を含むブログを見る
この本がKotlin抜きに非常に良い本でして、
Kotlin自体もいい感じだとわかったので、
例によってBrainF**kインタプリタを書いてみました(´・ω・)っ
これで「現場からは以上です」って感じなのですが、
以下は自分用のメモであり蛇足です...φ(・ω・`)
「今風の言語」とは何か?
1. 「人間」にとって都合の良い言語
仕様を読んでみて、Kotlinは非常に「今風の言語」だと思ったのですが、
何をもって「今風」なのか・・・と考えてみたわけです
そもそも、一番CPUに近い言語は「アセンブラ」であり、
それをもうちょっと人が書きやすくしたのが「C」、
そこにオブジェクト指向のパラダイムを付加したのが「C++」や「Java」でした
「プログラムとは、本質的にメモリを操作する仕組みに過ぎない」というのは、
こちらの本にも書かれている本質的な話でして・・・
プログラムはこうして作られるプログラマの頭の中をのぞいてみよう
- 作者: 平山尚(株式会社セガ)
- 出版社/メーカー: 秀和システム
- 発売日: 2013/09/25
- メディア: 単行本
- この商品を含むブログ (5件) を見る
・・・Javaも極論を言えば
「mallocとポインタを言いかえただけ」と見なすことが可能ですΣ(・ω・ノ)ノ
そういったCPUというかアセンブラから派生した言語とはまた別に、
「人にとって都合の良いモデル・処理系」を提唱したのが「Lisp」でして、
その影響を受けたJavaScript*1やRubyは非常に柔軟です
しかし、「人にとって都合がいい」は「CPUにとっては重い」ってことなので、
Rubyも長いこと「遅くて使えない」と言われていたのが、
CPUの高速化によって価値が再認識されたわけです*2
「わかりやすく言いかえる」というのが「人間」にとっては重要で、
「オブジェクト指向」も本来的には「現実世界をモデル化する概念」ですし、
「関数型」も「数学の概念のモデル化」にすぎません
まあ、当時の関数型言語ブームは少々アカデミックに走りすぎて、
「なんかよくわからないけど難しい」になってしまっていたのはありますが(´-ω-)
今ではオブジェクト指向とか関数型の概念は、
もはやそのような単語が言語の文脈に出てこない程度には、
「当たり前のもの」として扱われるようになっております
2. 「型」の取り扱いと「設計思想」
さて、RubyもJavaも「オブジェクト指向のパラダイムを含んだ言語」ですが、
決定的に違うのが「型」の扱い方です
Javaは変数に型を要求するのが当たり前*3であり、
Rubyは「そのメソッドが呼べればOK」というゆるい縛りしかありません
(いわゆる「ダックタイピング」)
Rubyはその表現力ゆえに「Rails」という「実装された設計思想」を生み出し、
現在のWebフレームワークはほぼRailsに影響を受けているわけです
一方で、Webが肥大化するにつれ、
モノリシックなフレームワークで抱えられる規模を超えると、
「自由度が高いこと」は必ずしも利点ではなくなってきます
もちろん、先日書いたようにアーキテクチャ設計でカバーできる場合もありますが・・・
・・・ここまでコストを割けるのはかなり限られたケースでしょう
そもそも、どんな「できるエンジニア」であっても、
「人が認識できる規模」にはどうしても限界があり、
それを超えれば確実にミスを生みます
だからこそ、「設計上の制約」を「コードレベルで表現する」のが必要で、
その手段の一つが「型」と言えます
「じゃあJavaにすればいい」というのはよくわかるし、
実際に業務系システムではまだ圧倒的なシェアがあるのですが、
どうしても他の言語に比べて「お堅いので書きづらい」のはあります(´-ω-)
結局は「いちいち型を書く」のが面倒なのであり、もっといえば
「人が見ればわかることをいちいち書かないといけないのが冗長」ということでしょう
String hello = "Hello World!";
要は、「helloに文字列を代入してるんだから、
helloがStringなのわかるやん? わからんの(´・ω・)?」ということで、
いわゆる「型推論」ができないのか・・・ってことです
「人間にわかること」と「CPUにわかること」には乖離がありますが、
CPUの進化により、「現実的な時間」で推論が可能になったため、
最近の言語はだいたい型推論を備えています
最近のJavaにも一応備わっているらしいですが、
「関数型っぽい型=高階関数」までは扱えない・・・か、
扱いづらいか、対応がまだ不十分かのようです(´・ω・`)
(Java8で改善されたことは知っているものの、触れる機会がなかったので、
このあたりの私の理解はあいまいです)
そこで、「JVMで動く関数型言語」として「Scala」が出てきたし、
私も一時期は興味があったわけですが・・・
やはり、先ほども書いたように、HaskellやScalaのような言語は、
「純粋な関数型言語」を「アカデミックな思想」で目指しており、
「普通の人には難しい(と見える)」のが問題なのではないかと
Rubyが広まったのはその柔軟性もありますが、
やはり「プログラムを楽しく書きたい」という「思想」の面が強いわけです
良くも悪くも、「現実的な妥協」が入っている
Kotlinは「純粋な関数型言語」ではありませんが、
「高階関数」や「再代入不可」のような、
Rubyと同程度以上の関数型言語的なパラダイムを備えています
その上でKotlinの「思想」は「よりベターなJava」であり、
非常に「Javaとの連携」を強く意識しています
Javaのclassとの暗黙的相互運用な可能な点は、
まさに「現場が望んだのだからそうあるべき」という思想を感じます(`・ω・´) b
結局のところ、「今風の言語」の個人的な定義はこうなるのかなと
- 「思想」が感じられ、「現実的なバランス」に落とし込んでいる
- 関数型のパラダイムを「現実的に便利な部分だけ」引き継いでいる
- 過去に存在した言語との相互運用性を意識している
その意味で、JavaScriptに対する「TypeScript」と、
Javaに対する「Kotlin」は同じなんだろうな・・・と*4
考えてみると、TypeScriptもKotlinも(ついでに C# *5 も)「企業」が開発した言語です
それだけ、「現場の声」が反映されていたり、
「現場で使われるIDEとの連携」を意識している・・・ということですね
3. Rubyエンジニアから見たKotlin
Rubyのエンジニアからすると、
Kotlinは「Rubyっぽくて書きやすいJava」ですが、
明確な違いがあります
それは「変更に対してオープンかクローズか」という違いです
Rubyにおいて、あらゆるものは上書き可能であり、
それゆえに「黒魔術」とも呼ばれる柔軟なメタプログラミングが可能です
これを利用してgemにモンキーパッチをあてる・・・というのもよくあります
言いかえると、「誰かが勝手にまずいことをやってしまうことを防げない」ので、
ある人が良かれと思って変えたクラスの変更が、
他に波及して壊れる・・・ということもあります(´-ω-)
モンキーパッチにしても、当時はわかっていてやったとしても、
あとになると忘れてしまい、gemが更新できず、
右往左往する・・・ってことがよくあります
(ゆえに、私はgemやフレームワーク自体にパッチをあてるのは否定的です)
それはプログラマの質とかチームの問題である・・・という「思想」なのですが、
大規模なシステムでそういった「やってほしくないこと」を防ぐのは、
「現実的に考えると」難しいです
その点、Kotlinは「クローズ」がデフォルトで、
「必要な時に明示する」という「思想」です
クラスだけでなく、メソッド単位で宣言が必要なのは「面倒」ですが、
「面倒だから面倒ではない手段を探す」ように誘導しているのはあります
(これはRubyの設計思想も同じ)
また、「良くないことをしている場所」をあとから探すのが容易になるのも利点です
Javaでもアノテーションとかありますが、
「言語仕様で強制」はできませんからね(´-ω-)
だからRubyよりKotlinが優れている・・・ということではなく、
あくまで「適用範囲を良く考えよう」ということです
一般的なWebの文脈においてはRubyが楽だけど、
業務系システムですでにJVMの実績があればKotlinだよね・・・みたいな...φ(・ω・`)
冒頭の本は何がいいのか?
先ほどもちょっと挙げたこちらの本を、私は以前から絶賛しております
www.slideshare.net
この本のすばらしい点は、「とにかく実装を進めていって、
必要になったらあたらしい概念を導入する」というのを徹底している点です
なにしろ、「変数」が出てくるのが後半ってレベルです
同様に、先ほどのKotlinの本も、
「Kotlinの機能を必要になったら紹介する(という体で書かれている)」のが重要で、
「この機能はどういう時に使うと適切なのか?」が明確なのです(`・ω・´) b
- 作者: Josh Skeen,David Greenhalgh,吉川邦夫
- 出版社/メーカー: 翔泳社
- 発売日: 2019/02/14
- メディア: 単行本(ソフトカバー)
- この商品を含むブログを見る
なにしろ、「クラス」が出てくるのが後半ってレベルでして、
「高階関数をどのタイミングで使えばいいのか?」もわかるようになってます
この本でも一貫して貫かれていたのが「ベターJavaとしてのKotlin」であり、
その意味ではJavaを知らない人には少々難しくなりそうにも思えます
その点、題材を「ゲーム」にすることで敷居を下げており、
最後まで興味を持って読みやすく工夫されてます
正直、この本がなければ、今回の記事は書かなかったとというか、
インタプリタだけ書いて満足したと思います
訳本ではありますが、特に読みづらいところもなく、
コードの間違いが気になる以外は、全体としてよくできた本だと思います
Kotlinに興味がある方だけでなく、プログラム初心者にもお勧めです(´・ω・)っ
*1: 「ブラウザで動くLisp」を実装するつもりが、マーケティングの都合でJavaっぽくなってしまった・・・というのは有名な話ですね(´-ω-) でも、「関数を値として扱える」という本質を譲らなかったおかげで、柔軟性を備えているわけです(`・ω・´) b
*2: JavaScriptだって、初期には原始的なDOMの操作にしか使われてなかったのが、ブラウザの高速化により、今ではゲームすら動かせるわけですよね
*3: 最近は緩和されたようにも思いますが、それは裏に隠したってことであり、基本的には「型があるべき」という「設計思想」だと思います
*4: Rubyも今では独立した言語ですが、かつては「ベターなPerl」を意識していた時代があり、その名残が仕様の随所に見られます・・・が、だいぶ減りましたね