ペンギン村 Tech Blog

技術をこよなく愛するエンジニア集団が在住するペンギン村から、世界へ役立つ(かもしれない)技術情報を発信する技術系ブログです。某アラレちゃんが済む村とは一切関係ありません。んちゃ!

Swift エンジニアが学ぶ Rust - 0.序章

Rust はとても良い言語です、 TRust me。

ダジャレから始めるのは初めてでしょうか。Rust 勉強中の tobi462 です。

私はプログラミング言語を学ぶのが好きな畑の人間でして、最近では Rust を学んでいるのですが、これがなかなかどうして面白いのです。

Love Swift ?

おそらく私の一番得意な言語は Swift か Java なわけですが、どちらが好きかと言われれば断然 Swift です。

Haskell のような代数データ型としての enum はとても好きですし、Protocol Oriented Programming や extension による既存クラスの拡張、switch によるパターンマッチも好きです。

機能やシンタックスが多すぎて覚えるのが大変な点や、switch によるパターンマッチの読みづらさといった点、バージョンアップごとに破壊的仕様変更が入る(これほど互換性を意識しないプログラミング言語も珍しいのではと思ったりします)などの点を除けば、 概ねよく出来た言語だと感じていました。

Rust ?

そんな中、Rust という一匹のプログラミング言語に出会いました。 www.rust-lang.org

Mozilla が主導になって開発しており、ポスト C++ として期待される言語だとか、高速だとか安全な並列性だとか、なんとかかんとか。

そして他の言語では聞かないような「所有権モデル」なるものを有しているとか。

Rust の第一印象

そういうわけで Rust を軽い気持ちで学び始めたわけです。

そして感じたのは、所有権モデルの難しさです。

いえ、所有権モデルの考え方自体は難しくないのです・・・そう感じるのです。しかし、実際にコードを書いてみるとコンパイルが通せないことこの上なしです。

コンパイラはとても分かりやすいエラーメッセージを出力してくれます。曰く、ライフタイムがどうとか、借用されてるとか、ムーブされてるとか・・・。

なるほど分からん、というわけです。

HTTPサーバを練習がてら書いてみたのですが、 コンパイルエラーが直せなくて泣きたい気持ちになりました。

そんなわけで、ポスト C++ として優れた言語であろうことは感じつつも、学習コストに見合う言語だとは感じませんでした。

2nd Edition 日本語版

それから1年くらいは Rust を触らなかったように記憶しています。

そんな折に、以下のツイートが TL に流れてきました。

[https://twitter.com/yyu/status/985924298282975237:embed]

Rust のコミュニティが分かりやすい学習リソースを目指して 2nd Edition をリリースしたのは聞いていましたが、英語なのでちょっと面倒だと思って読んでいませんでした。

その日本語版が読めるということで、懐かしさもあり読んでみることにしました。

Rust の美しさ

2nd Edition 日本語版を読み進めていくうちに、私は Rust に夢中になっていました。

当初、複雑だと思った Rust の機能は十分によく考えられて用意されており、分かりづらいと思っていた一部のシンタックスも機能を本質的かつ端的に表現しており、それでいてヒューマンリーダブルとコンパイル速度の両立を計っているのだと感じました。(褒めすぎ?)

そして Rust の機能の理解が進むに連れ、Rust のコードの見え方が少しずつ変化していくことにも気づきました。

これは Haskell を学んだ時の感覚に似ている。そう感じました。

Rust の特徴

先ほどから Rust の言語的な紹介をまるでしていませんでしたが、Rust は以下に焦点をあてた言語であるととされています。

  • 速度
  • 安全性
  • 並行性

速度

速度は C++ と同等レベルを目指しており、関数型プログラミングや Trait といったモダンな機能を取り入れつつも、実行速度は C++ と同程度になっているようです。

一般的にプログラミング言語が高機能になる、すなわち抽象化が進むほど実行時のオーバーヘッドは高くつくものですが、Rust コンパイラは「ゼロコスト抽象化」という考え方を元に、実行時のオーバーヘッドが限りなく少なくなるように設計されています。

安全性

メモリ管理について記憶をたどると C++より後の言語はだいたいガベージコレクタ(GC)を採用している印象があります。

GC はメモリ管理を自動化しようという考え方で、実行時のオーバーヘッドと引き換えにプログラマはメモリ管理から開放され、より生産的になれるというものでした。なお、 Swift で採用されている ARC も GC にあたるようです。

C言語の時代ではメモリ管理はプログラマの重要な仕事でしたが、ハードウェアの圧倒的な進化もあり、現代のプログラミング言語ではメモリ使用量やレイアウトを意識する機会も圧倒的に減ったのではないかと思います。

GC は実際のところ 1960 年代の Lisp でも実装されていたものらしいですが、それはさておきプログラマはメモリ管理から開放されたおかげで、メモリリークやダングリングポインタなどのバグを圧倒的に減らせたとされています。

これは Joel on Software | Joel Spolsky, 青木 靖 |本 | 通販 | Amazon などでも語られていました。

GC というメモリ管理手法は、手動管理に比べると圧倒的に安全であり、解放済みのメモリアドレスにアクセス(ダングリングポインタ)して未定義動作を引き起こしたり、あるいはバッファオーバーフロー脆弱性なども防ぐことが出来ました。

とはいえ GC も万能というわけではなく実行時のオーバーヘッドがつきまといます。

Java では フルGC により一時的にプログラムが停止してしまう問題はよく知られています。

さて前置きが長くなりましたが、 Rust の所有権システムでは、GCのようなオーバーヘッドを発生させることなく、かつ手動管理のような非安全性を排除したメモリ管理を採用しています。

これは一言ではとても説明できないので今後に譲りたいと思いますが、端的に言えばコンパイル時にメモリ安全性を確保するアプローチ、といったところでしょうか。

並行性

プログラミングにおける並行性はとても難しいものです。

マルチスレッドのプログラミングは、誇張するわけでもなくシングルスレッドのプログラミングよりはるかに難しく、それを安全に動作させるというのはさらに難しいです。

現代では Actor モデルとして知られる、メッセージ受け渡しモデルの並行プログラミングが主流になりつつあると感じられますが、これは GC と同じくオーバーヘッドがあり、ハードウェアの限界まで搾り取る必要のあるプログラムには向いてないとされます。(とは言え、Go言語の近況をみるとそれも分かりません)

Rust では OS の生スレッドをAPIとしてサポートしつつ、並行プログラミングにおける課題であるデータ競合に対して、コンパイル時に誤りを検出しようというアプローチを取っています。

すなわちオーバーヘッドなしでOSのスレッドを利用しつつも安全な並行性を実現できるということです。

Rust は最強言語の夢を見るか?

多くのプログラミング言語あるいはミドルウェアやFWがそうであるように Rust も適材適所でしょう。Rust が向いている領域もあれば、Rust が向いてない領域もあるでしょう。

スマートフォンがいくら便利だからと言って、それを缶詰の蓋をあけるのに利用する人はいないでしょう。(いないよね?)

なぜ、わざわざこんな話を持ち出したかというと、(Rust を学習中の身ではあり現時点の予想に過ぎないのですが)おそらく Rust が向いている、すなわちトレードオフに見合うソフトウェア開発プロジェクトというのはさほど多くは無いのではないかと想像しているためです。

現代の潤沢なハードウェアにおいて、ハードウェアの限界まで絞りだすようなパフォーマンスが必須の要件となるプロジェクトはさほど多くはないでしょう。

もちろん OS や ドライバ などのソフトウェア開発などには向いているでしょうが。

教養としての Rust

さて、それを考えると Rust を学ぶべきでしょうか?

プログラミング言語の人気度ランキングにしたがって、職につきやすい言語を学ぶべきではないでしょうか。例えば、JavaとかScalaとかRubyとか(実際、高給なのはScalaなんですかね?)。

それでも私は Rust を学ぶ価値があると感じます。

それは古今東西の偉大なプログラマが Lisp を学ぶべきだと言ってきたのと同じ理由であり、すなわちより良いプログラマになるために Rust を学ぶべきなのではないかということです。

Rust の所有権システムはメモリ管理についての考え方をあらためさせてくれますし、シンタックスと調和の取れたモダンな言語仕様からも多くの刺激を得られます。

Swift はかなりモダンな言語だと思っていましたし、実際モダンな言語だと思いますが、それでも Rust を学んでいくと見えてなかったものが見えてくる気がしました。

特に C言語やC++などの手動メモリ管理をする言語を触ったことがなければ、Rust の所有権システムから得られる学びというのは大きいと感じます。(と言いつつ、C言語とかで低レベルなメモリ管理を学ぶほうが良いのかな、という思いもあったりします)

まぁ、つまり教養として Rust を学ぶというのはとても有意義なことで、それはプログラマとしての考え方を広げてくれるのではないか、そんな風に私は感じるわけです。

D.C. - ダ・カーポ -

という訳で、話は最初に戻ります。

すなわち Swift エンジニアの私が Rust を勉強していこう というわけです。

学習するならアウトプットすべきですし、私が学んだ知識を広く共有することで、誰かの役に立てばそれはプログラマ冥利に尽きるというものです。

そんなわけで Rust の学習記録をブログ記事として連載していきたいと思います。

まぁこういうのは最初だけモチベーション高くて、すぐに飽きてしまう(プログラマとしては決して悪くない正確かもしれませんがそれはさておき)かもしれませんが、まぁ続けていけたらなと思います。

最初の記事にこんなにエネルギーを使って果たして良いものかと思いつつ、このあたりで。