RとRustの現状確認 2023

@yutannihilation

ドーモ!

Hiroaki Yutani

今日話したいこと

「Rustをどう使うか」
ではなく
「Rustを使うとはどういうことか」
について話したい

これまでのあらすじ

2021年5月の発表:

あれから2年…
あなたの人生は
進捗していますか??

進捗まとめ

  • Rust: めちゃめちゃ進捗している
  • R(CRAN): まあ進捗している
  • extendr: そんなに

Rustとは

Rustとは

効率的で信頼できるソフトウェアを誰もがつくれる言語
(公式ウェブサイトより)

  • 効率: 速い
  • 信頼性: 所有権モデルと型システムで、メモリやスレッドに関するバグが起こりにくい

広がるRustの輪

広がるRustの輪

→ これまで、低レベルへのアクセス性や速度という面でC++でなければ難しかったところがRustに置き換えられつつある

RustがC/C++より優れる点

  • コンパイラのチェックが厳しいのでバグが混入する可能性が減る
  • 標準でパッケージマネージャがあるので、C/C++よりも依存関係で悩むことが少ない
  • OSに組み込まれていないのでしがらみが少ない(私見)

C++はオワコン、これからはRustの時代だ!

  • C++で書いてるRのパッケージも、これからはRustを使いましょう!
  • なんならR本体もRustで書きなおそう!

→ …ほんとに?

広がるRustの輪?

  • Linux → まだドライバの開発のみ、将来的にもすべてがRustに置き換わるかは不明
  • Windows → ほんの一部での利用
  • Firefox → Rust製のブラウザエンジンServoは、開発から10年以上経つのにまだC++製のエンジンを置き換えられていない
  • Chrome → 当面はC++からRustを呼び出すという一方通行、それも本体ではない部分だけ

RustとC/C++の間の壁

RustはC/C++を置き換える存在かもしれないが、今あるC/C++のコードをRustに置き換えるのは簡単ではないことも多い。

  • Rustは安全だが、C/C++と組み合わせるならその安全圏から出ることになる
  • 対応する型がなかったりして、データの受け渡しが難しい
  • C/C++の定番ライブラリに匹敵するものがRustにないことも多い(例:geo系)

今日話したいこと

「Rustをどう使うか」
ではなく
「Rustを使うとはどういうことか」
について話したい

今日話したいこと

  • Rパッケージ開発者の方へ
    • Rustは最高だけど、RのパッケージでRustを使うのはそれほど最高ではない。
    • とはいえ、Rustは使えます。
  • Rユーザーの方へ
    • この先生きのこるには。

なぜRとR以外の言語が組み合わせられるのか

※免責事項

この辺りはまじで理解できていないので、かなり適当なことを言ってる可能性があります。

鵜呑みにせず、自分で調べましょう!

R’s C API

「C API」とは?

  • C/C++にとっては、API
  • 他の言語にとっては、実質ABI

APIとABI

  • API: ソースコードレベルで関数やデータの仕様を規定したもの。同じプラットフォーム上で、同じコンパイラでコンパイルすれば互換性がある。
  • ABI: バイナリレベルで関数やデータの仕様を規定したもの。

ABIのイメージ図

“stable” ABI

  • ABIとは「バイナリの仕様」なので、当然どのコンパイラにも仕様はある。
  • ただし、コンパイラのバージョンによっても変わる。

「ABI」と言う時、欲しいのは言語やバージョンに寄らない「stableな」ABI。

何もかもが不確かなこの世界に確かなものなどあるのか?

→ 事実上、CのABIが共通言語として使われる

  • 本当は「CのABI」は存在しないが、OS内部でも使われる都合上、 同じOS・アーキテクチャであれば同じABIになるはず。
  • モダンなプログラミング言語にとっては表現力が足りないこともあるが、選択肢がない

参考) その他のstable ABI

  • Swift: mac限定だが、stable ABIを持っている
  • WebAssembly: ブラウザ向けにもOSネイティブ向けにもまだstableなABIはないが、用途から考えるといずれできる?

参考) 「CのABI」とは?

R↔︎Rustのイメージ図

R↔︎Rust

  • Rは、C ABIがある
  • Rustも、C ABIを持つバイナリを生成できる

→ お互いにC ABIを通じて関数を呼び出し合う

(ここまではあまり問題ない)

R↔︎Rustのむずい点

  • データは、数値は値渡しだが、基本的にはポインタを渡してメモリを直接参照する
    • 互いのリソース管理がずれると死
    • 互いに想定するデータ型が一致しないと死
  • エラーが発生すると死
  • C runtimeが異なると死?

互いのリソース管理

R

PROTECT()でreference countしている1。reference countが0になったオブジェクトはGCの対象になる。

Rust

Rustは賢いので、オブジェクトが使われなくなったらすぐにデストラクタが走る。

つまり?

  • PROTECT()を忘れたままRustからR側のオブジェクトを参照しようとすると、気が付くと消えていてsegfaultで死
  • Rust側で作成したオブジェクトが、RustからRにポインタで返す頃にはすでに消えていてsegfaultで死
  • R側で作成したデータの所有権をRust側に移してしまって、勝手にメモリ解放してしまってsegfaultで死

死ななくても苦しい

  • メモリが解放されないようにしたはいいが、そのまま忘れていてメモリリーク
  • データをコピーするようにすれば安全だが、都度都度コピーしてると遅い

補足: 「メモリを直接参照」と言ったがあれは嘘だ

  • ALTREPの場合、ベクトルの中身がメモリに展開されているわけではないので直接参照できない。
  • どうするかというと、
    • RのC API経由(VECTOR_ELT()とか)で値にアクセスする
    • 一度すべて展開してしまう

補足: 「メモリを直接参照」と言ったがあれは嘘だ

  • RのC API経由(VECTOR_ELT()とか)で値にアクセスする
    → 読むだけでも状態を変更してしまうので、これをうっかり並列に実行すると死ぬ

  • 一度すべて展開してしまう
    → 安全だが、非効率

エラーが発生すると死

  • Rのエラーはlongjmpなので、スタックをunwindする
  • しかし、C ABI越しのunwindはundefined behavior(Rust側のデストラクタが呼ばれないとか、そういう話らしい)で危険

(これはまあ、C-unwind ABIがstableに入れば解決する話らしい)

C runtimeが異なると死?

これは主にWindowsの問題で、RはUCRTだが、RustはまだMSVCRT(たぶん)という違いがあり、 そのために予期せぬエラーが起こるのでは、という話がある。

でもまだ遭遇したことなくてよくわからない。。おれに聞かれても。。。。。

ここまでのふりかえり

  • どうして…?
  • Rustを使うと安全、メモリの管理とか自分で気にしなくてもオッケーでラクチン!、のはずだったのでは…?

extendr?

  • extendrを使っておけば、初歩的なミスは割と防げる
  • それでも、何も知らずに使えるほど楽にはならないかも…
  • 特に、unwindの話とかC runtimeの話とかはextendr側ではどうしようもない

Rustを使ったRパッケージを作るには

…という話はしません

先生の次回作にご期待ください!

Rustを使ったRパッケージを配布するには

Rustを使ったRパッケージ配布の難しい点

install_github()だと、ユーザーにRustをインストールしてもらう必要があるが、トラブルが多い

  • Windowsは、ツールチェーンがMSVC版とGNU版とあってセットアップがやや複雑
  • macOSは、PATHが通らないことがある
  • そもそも管理者に許可されていないことも

Rのパッケージは2種類ある

  • source package: ソースコードの状態。インストール時にユーザーの手元でコンパイル。
  • binary package: あらかじめコンパイルされている。インストール時にはファイルが展開されるだけ。macOS・WindowsでCRANからインストールする時はこっち。

→ なるべくbinary packageで配布したい!

ここで朗報です

  • CRANのマシンにRustがインストールされた!
  • R-universeができた!

CRANのマシンにRustがインストールされた!

R-pkg-develメーリングリストでのやりとり

All we need is the rustc/cargo toolchain to be installed on the CRAN win/mac builders (it already is on Fedora/Debian)

(意訳:いっやー、RustがCRANにインストールされてたらワシもこんなことせんでええねん。インストールされてたら万事解決なんやけどなあ…)

CRANのマシンにRustがインストールされた!

R-pkg-develメーリングリストでのやりとり

sorry, I think you misunderstood: CRAN machines have the compilers

(意訳:インストールされてるで)

CRANのマシンにRustがインストールされた!

  • 以前からLinuxマシンにはRustがインストールされていたが、今はWindows・macOSにもRustがインストールされている
  • ただし、R 4.1用のWindows Serverは古すぎてRustをインストールできなかったらしいのでDepends: R (> 4.1)を指定する必要がある

CRANのマシンにRustがインストールされた!

  • そんなわけで、Rustを使ったパッケージをCRANにリリースするのが少し簡単になった
  • ただし、Rustのバージョンはまちまち(これは、今後難しい問題になりそう)

CRANリリースに成功したユーザーの喜びの声

CRANにあるRust系パッケージの例

  • gifski: GIFアニメーション作成
  • prqlr: PRQLをSQLに変換する
  • string2path: 文字をプロット可能なパスのデータに変換する

R-universeができた!

R-universeとは?

  • rOpenSciのJeroen Ooms氏が管理する、Rパッケージをビルド・配布するプラットフォーム。
  • 誰でも無料で、審査なしでパッケージを公開することができる。
  • GitHub Actions CIを利用している。

R-universeのいい点

  • CRANと違ってパッケージの審査がないので気軽に使える。どんなパッケージでも、ビルドが通りさえすれば問題ない。
  • GitHub Actionsでシステムが組まれているので、プラットフォーム側に問題があっても自分で調査できる

R-universeの気になる点

  • (信頼と安心のrOpenSciブランドとはいえ)Jeroenの個人プレーで運営されている
  • GitHub Actionsには今のところArm macOSのrunnerが存在しない

パッケージ配布方法まとめ

CRAN R-universe GitHub
審査 あり なし なし
バイナリ 1 2 ×
Rust version not
最新
最新? -

補足: CRANはRustをサポートしたいのか?

  • 正直、よくわからない
  • RコアチームやCRANメンテナにRustがわかる人はいなさそうだが、サポートしようという意志はあるっぽい
  • ただ、「動くかわからないものをCRANに突っ込むな!」というキレ気味な空気も感じる

補足: CRANはRustをサポートしたいのか?

  • Windowsについては、C runtimeの違いの問題を重く見ているらしく、「RtoolsにRustを入れないとダメそう」という話になっている(メールでそう話してるだけなので知らんけど)

ここまでのふりかえり

  • Rustを使ったRパッケージの配布は、この2年くらいでかなりやりやすくなった。
  • CRANもRustをサポートしたくないわけではなさそうなので、未来は明るい?

Rustを使う理由

そこまでしてRustを使う理由がある?

  • 配布が楽になったとはいえ、前半で見たように、RustをRと組み合わせて使うこと自体はなかなか楽にならない
  • 楽にならない = C/C++を使うのとそれほど変わらないのでは?

Rustを使うかどうかの判断基準

  1. Rとのデータのやり取りが少ない
  2. Rustにしかないライブラリがある
  3. C++を知らない

Rとのデータのやり取りが少ない

  • RとRustの境界が大変なだけで、Rustだけで完結する部分は困らない。
  • 例えば、Rから受け取るのは数個のパラメータで、メインはRust側での重い計算、みたいな場合はやる価値がある。

Rustにしかないライブラリがある

  • 今はあまりないかも
  • でも、ゼロから新しく書かれるものはRustの採用が増えている
  • 数値計算系とかgeo系とか、積み上がった資産をゼロから書き直すのは厳しい分野もあるかも。

参考: Chromeの場合

The ecosystem is enormous (96k+ crates on crates.io) and growing, with investment from the systems development industry at large, including Google. Chrome relies heavily on third-party code, and we need to keep up with where that third-party investment is happening.
(Google Online Security Blog: Supporting the Use of Rust in the Chromium Project)

参考: Chromeの場合

(意訳)

Rustのエコシステムには産業界も含めて多くの人や金がつぎ込まれていて、今後も発展していく。 Chromeは、様々な外部ライブラリによって成り立っているので、業界がRustに注力するならChromeも注力していく必要がある。

参考: Chromeの場合

![](./images/お金こそパワー.gif)1

Rustにしかないライブラリがある

  • 部分的とはいえ、LinuxやChromeに採用されたというのは大きい
  • 人と金が集まっているのは事実なので、今後増えていく
  • ので、RコアチームもいずれはRust対応を真面目に考える時期が来ると思う

C++を知らない

  • Rustは、C++よりは初心者に優しい
    • ドキュメントや書籍が充実している
    • コンパイラのエラーやエディタの補助がめちゃくちゃ親切なので、それに従って直していけばだいたいなんとかなる
    • 人が優しい(気がする)

逆にこういう時は考え直した方がいいかも

  • C++からRustにすると速くなりそう
    → まじで場合によるので、速度のためだけにやるのはやめた方がいい(勝ち筋が見えてるなら別)

  • C++だと謎のエラーが出るのでRustにすると安全そう
    → たぶんRustの方がましだけど、理解せずに使えるわけではない

まとめ

まとめ

  • Rustは最高だけど、RのパッケージでRustを使うのはそれほど最高ではない
  • とはいえ、パッケージ配布はだいぶインフラが整ったので、やってみるといいと思う
  • 今後Rustでいろいろ面白いことができるようになっていくと思うので、興味が出たらやってみるといいと思う

何かあれば

r-wakalangに#rustというチャンネルがあるので、そこで何でも聞いてください!(答えられるとは言っていない)