- 20年以上C++を使ってきた筆者が、Rustの利点を再発見するきっかけとなったMatt Godboltの講演を紹介している
- C++では型の取り違えによるミスがコンパイラで適切に検出されないが、Rustはこれをコンパイル時に強力に防ぐ
- Rustは単なるメモリ安全性にとどまらず、APIの誤用防止にも有利な設計になっている
- とりわけランタイムの入力処理においても、Rustはエラーを明示的に処理することを強制し、危険を減らす
- 結局のところ、言語設計が開発者のミスを防ぐ強力な道具になり得ることを示す事例である
序論
- Matt Godboltの講演 "Correct by Construction" は、C++のAPI設計の問題に光を当てており、これはRustの哲学とも一致している
- Rustの強みを理解するうえで、この講演は良い入門資料である
What's in a type — C++の限界
void sendOrder(const char *symbol, bool buy, int quantity, double price) のような関数シグネチャは、非常にエラーを起こしやすい
bool, int, double などの基本型だけを使うと、型を誤って渡してもコンパイラは警告しない
using Price = double のような型エイリアスには、実際の型を区別する機能がない
- クラスと
explicit コンストラクタを使って Quantity, Price を作ると、コンパイラが一部のエラーは検出してくれるが:
- 負の値も許容されてしまい、これはランタイムでしか問題にならない
static_assert とテンプレートを活用すれば、コンパイル時チェックを強制できる
- しかし依然として
atoi のようなランタイム変換は、整数オーバーフローを引き起こし、コンパイラは検出できない
Rustはどう違うのか?
- 同じ関数定義でも、Rustは型の不一致をコンパイル時点で明確なエラーとして示す
struct Price(pub f64); struct Quantity(pub u64); のような新しい型定義も簡単で、負の入力の排除も自然に機能する
"string".parse::<u64>() のように、ランタイムの文字列変換でも明示的なエラー処理が必要になる
.expect() で値を強制的にアンラップするとランタイムクラッシュが発生するが、これはC++の沈黙したままのエラーよりは良いという点が強調されている
結論
- Rustは単なるメモリ安全性以上に、APIの誤用防止、コンパイル時チェック、明確な型システムを通じて開発者を保護する
- 言語設計の力が開発者のミスを未然に防げることを示している
- Rust初心者は**借用チェッカー(borrow checker)**と格闘する難しさを経験するかもしれないが、これは時間が経てば解決される
- C++は歴史的に多くの発展を遂げてきたが、それでもRustのような根本的な安全性と明確さを提供するのは難しいことが明らかになる
参考
4件のコメント
C++の欠点として挙げられる部分の多くは、ほとんどがC言語との互換性のために維持されている内容なんですね。
Cとの互換性を捨てて開発できるように変えることはできるのでしょうか?
unsafeを提供しなかったほうが、もっとよかったのにと思います。根本言語 = Rust
Hacker Newsの意見
Rustの最大の利点は、エラー伝播の方式が
Result型に統一されていること。例外処理やさまざまなエラー返却方式を気にする必要がない点が魅力?ショートハンドとResultの関数型インターフェースのおかげで、エラー処理が楽しく簡単に扱えるC++に対する不満は多い。特に、多くのルールを覚えなければならず、1つでも間違えるとコードが脆弱になりうる点が問題
現在書いているC++コードはRustに似ている。明示的で強力な型、明確なライフタイム管理などを使っている
暗黙的変換に関するC++の問題は、言語というよりライブラリの問題
Rustにはキーワード引数や名前付きタプルがないため、
Args/Options構造体を使うのが不便な面がある-Wconversionオプションは特定の変換問題を検出できるが、すべてのケースに適用されるわけではないRustのほうが優れている点は、暗黙的な数値変換がないこと。C++では
atoiを使わず、STLの変換関数を使うのがよいSQLの制約条件やpydanticのカスタム型・バリデータに似た機能は、RustやGolangにはまだない
MattとBen Radyのプログラミングポッドキャスト "Two's Complement" に興味があるなら、聴いてみる価値がある