18 ポイント 投稿者 xguru 2024-11-04 | 12件のコメント | WhatsAppで共有

うまくいったこと

  • リライトは小さなステップで進められ(段階的、stop-and-go)、うまく動作し、新しいコードは読みやすく理解しやすくなった
  • コード全体を見渡せるようになったことで、性能最適化の機会を得られた
  • およそ1/3〜1/2の未使用コードを削除した。RustやGoのような現代的なプログラミング言語は、デッドコードをよりよく見つけて開発者に知らせてくれる
  • 範囲外アクセスやオーバーフロー/アンダーフローを心配しなくてよい
  • 組み込みのテストフレームワークが非常に有用
  • CMakeファイルを削除できてうれしい

うまくいかなかったこと

依然として未定義動作を追跡しなければならない

  • C/C++からRustへの段階的なリライトでは、多くの生ポインタとunsafe{}ブロックを使わざるを得なかった
  • Rustのルールはunsafe内でも適用されるが、コンパイラはチェックしないため、未定義動作が簡単に発生する
  • unsafe内では、「複数の読み取り専用ポインタ XOR 1つの可変ポインタ」というルールを簡単に破れてしまう
  • Miriがこれを検出してくれる救世主になった

Miriは常に動作するわけではなく、依然としてValgrindが必要

  • 暗号ライブラリのように、Cやアセンブリで書かれた部分を持つライブラリを使うと、Miriは動作しない
  • Miriでチェックされないunsafeコードが多くある
  • 一部のテストはvalgrindで実行する必要があった

依然としてメモリリークを追跡しなければならない

  • C APIの一般的なパターンは、MYLIB_init()でメモリを確保し、MYLIB_release()で解放するというものだが、MYLIB_releaseの呼び出しを忘れやすい
  • Rust開発者はRAIIでラッパーオブジェクトを作りたくなるが、C APIを使うテストではこの機能を使えない
  • 複雑なロジックでは、クリーンアップ関数を常に呼び出すのが難しい。Cではgotoを使って解決するが、Rustはサポートしていない
  • deferクレートで解決したが、借用チェッカーはこれを好まない

クロスコンパイルは常に動作するわけではない

  • Miriと同様に、Cやアセンブリで実装された部分を含むライブラリを使うと、cargo build --target=...はそのままでは動かない

Cbindgenは常に動作するわけではない

  • CbindgenはRustコードベースからCヘッダを生成するためによく使われるが、限界やバグがある

不安定なABI

  • Optionのような便利な標準ライブラリ型に安定したABIがないため、repr(C)アノテーションを使って手動で複製しなければならない

カスタムメモリアロケータのサポート不足

  • 多くのCライブラリでは、ユーザーが実行時にアロケータを提供できる。Rustでは、コンパイル時にしかグローバルアロケータを選べない
  • リソース解放の問題はアリーナアロケータで解決できるが、Rustでは慣用的ではなく、標準ライブラリとも統合されていない

複雑さ

  • FFI処理のためにUnsafeCellRefCellMaybeUninitPinなどを使う必要があり、複雑さが増す
  • 純粋なRustだけでもすでに複雑なのに、FFIレイヤーまで加わると怪物になる
  • Rustの複雑さのせいで、このコードベースでの作業を断った開発者もいた

結論

  • Rustへのリライトには概ね満足しているが、一部の領域では期待外れで、想像していたよりはるかに多くの労力がかかった
  • Cと多く相互運用するRustは、純粋なRustを使うのとはまったく別の言語のように感じられる。摩擦が多く、落とし穴も多い。Rustが解決したと主張するC++の多くの問題は、実際にはまったく解決されていない
  • Rust、Miri、cbindgenなどの開発者には深く感謝している。彼らは驚くべき仕事を成し遂げた。それにもかかわらず、C FFIを多用する際の言語とツールは未成熟で、ほとんどv1.0以前のように感じられる
  • unsafeの使い勝手、標準ライブラリ、ドキュメント、ツール、不安定なABIなどが今後改善されれば、もっと楽しい体験になるだろう
  • MicrosoftとGoogleもこれらすべてを感じているからこそ、この領域に実際の資金を投じているように見える
  • まだRustを知らないなら、最初のプロジェクトでは純粋なRustを使い、FFIの話題には距離を置くのがよい
  • 当初はこのリライトにZigやOdinを使うことも検討したが、企業の本番コードベースでv1.0以前の言語を使いたくなかった。今では、その経験がRustより本当に悪かったのか気になっている。おそらくRustのモデルはCのモデル(あるいはC++のモデル)と本当に相性が悪く、一緒に使うと摩擦が大きすぎるのだと思う
  • 今後同様の作業をするなら、Zigを強く検討するだろう。誰かが「とにかくRustで書き直せばいい」と言うたびに、この記事を見せて気が変わったか聞いてみてほしい

12件のコメント

 
bus710 2024-11-05

Zig はまだ pre v1 ですが、多くの C ライブラリを使えるので、思ったより実用的ではあります。動いている C ベースのプロジェクトに何かを載せるなら、Rust より Zig のほうが向いているかもしれません。

 
ahwjdekf 2024-11-04

Rustを見ていたとき、unsafe というキーワードを見た瞬間、ぞくっとする感じがした…

 
jkliop890 2024-11-04

私は、RustがC++の抱える慢性的な問題を解決できるとは思っていません。これは文法的な観点というより、実務的な観点からです。

理由は次のとおりです。

  1. すでに非常に多くのProductionがC/C++を使っています。そして安定してうまく動いています。その大半は、あえてこれをRustに移植しようとはしません。

  2. そもそもハードウェアは参照カウントを前提に作られていません。C/C++が使われる多くのケースは、ハードウェア、OS、ドライバ、バイナリ層を高速に制御するためですが、Rustを支えるには低レベル開発者が結局unsafeを活用してリソースのライフサイクルを直接管理しなければならず、これもまた大きなコストです。

私は、筆者の経験は、言語が潜在的に持つ価値や理論的な話よりもさらに重要だと思います。
実際、C/C++レベルの言語が必要とされる分野のリソース管理の水準は、Rustで置き換えるには帯に短したすきに長しのようなものだと感じます。

 
cosine20 2024-11-04

この記事もまた、Rustを誤解したまま飛びついていますね。
内容を見ると、Rustの外部と頻繁にやり取りしなければならないライブラリのようですが、その時点ですでに泥臭くならざるを得ません……。そもそもネイティブ言語で泥臭くならないものはなく、Rustはそれを言語レベルで安全に包んでいるだけなので、言語の外部との接点が増えるほど利点はかなり薄れていきます。

Rustが解決したと主張するC++の多くの問題は、実際にはまったく解決されていない

ある程度はその通りですが、元記事の開発環境では解決できないのが当然で、Rustを万能薬のように考えて取り組んだのが問題だと思います。

 
kotlinc 2024-11-04

私は、C/C++をRustへ段階的に移行する過程ではunsafeを使わざるを得ないので、Rustに移行する意味はない、Rustへ段階的に置き換えるよりもZigを選ぶつもりだ、という意味に感じましたが、本文のどこにRustの外部と頻繁に通信しなければならないライブラリだと書かれているのでしょうか?

 
cosine20 2024-11-04

FFI を使うということは、すなわち Rust の外部と通信するということですよね。
そして本文を見ると、単純に何らかの状態や簡単なデータをやり取りする程度で終わるのではなく、内外が複雑に相互作用しているように見えます。

 
kotlinc 2024-11-05

Cで書かれたライブラリを段階的にRustへ置き換えるなら、FFIは避けられないのではありませんか? プログラムの小さな部分をRustに置き換え、残りのC部分はFFIで処理することになるはずですが、そうした作業を外部との通信と表現されたのでしょうか? もしそうであれば、元の筆者がRustに懐疑的になるのは自然なことだと思います。コード全体を一度に書き換えない限りRustの利点は得られないので、Zigを勧めるのでしょう。

 
cosine20 2024-11-05

^-^

 
savvykang 2024-11-04

unsafe な部分がソースコード上で明示的に示されるため、プログラムのエントリーポイントから unsafe ブロックを使わない限り、FFI の影響範囲をすべて特定できて有用だろうと期待していたのですが、筆者にはあまり実感がなかったようです。

 
carnoxen 2024-11-04

そもそもFFIを使った時点で、安全な設計は事実上不可能になったようなものです。

 
cosine20 2024-11-04

その通りです。

 
kohs100 2024-11-04

そうですね、unsafe をべた塗りしたと堂々と書いておきながら、解決されなかったとは……