Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Rustがどんな言語なのか説明する時に考えたこと
Search
Igaguri
October 05, 2019
Programming
0
190
Rustがどんな言語なのか説明する時に考えたこと
Rust Kansai Meetup #5 発表資料
https://rust-kansai.connpass.com/event/148437/
Igaguri
October 05, 2019
Tweet
Share
Other Decks in Programming
See All in Programming
ペアプロ × 生成AI 現場での実践と課題について / generative-ai-in-pair-programming
codmoninc
0
740
C++20 射影変換
faithandbrave
0
560
Hypervel - A Coroutine Framework for Laravel Artisans
albertcht
1
110
deno-redisの紹介とJSRパッケージの運用について (toranoana.deno #21)
uki00a
0
170
『自分のデータだけ見せたい!』を叶える──Laravel × Casbin で複雑権限をスッキリ解きほぐす 25 分
akitotsukahara
1
600
イベントストーミング図からコードへの変換手順 / Procedure for Converting Event Storming Diagrams to Code
nrslib
1
580
たった 1 枚の PHP ファイルで実装する MCP サーバ / MCP Server with Vanilla PHP
okashoi
1
220
ソフトウェア品質を数字で捉える技術。事業成長を支えるシステム品質の マネジメント
takuya542
0
770
LINEヤフー データグループ紹介
lycorp_recruit_jp
0
1.7k
なぜ「共通化」を考え、失敗を繰り返すのか
rinchoku
1
620
LT 2025-06-30: プロダクトエンジニアの役割
yamamotok
0
670
プロダクト志向なエンジニアがもう一歩先の価値を目指すために意識したこと
nealle
0
120
Featured
See All Featured
We Have a Design System, Now What?
morganepeng
53
7.7k
Performance Is Good for Brains [We Love Speed 2024]
tammyeverts
10
940
Thoughts on Productivity
jonyablonski
69
4.7k
I Don’t Have Time: Getting Over the Fear to Launch Your Podcast
jcasabona
32
2.4k
Site-Speed That Sticks
csswizardry
10
670
Practical Tips for Bootstrapping Information Extraction Pipelines
honnibal
PRO
20
1.3k
CSS Pre-Processors: Stylus, Less & Sass
bermonpainter
357
30k
Done Done
chrislema
184
16k
A Modern Web Designer's Workflow
chriscoyier
694
190k
GraphQLの誤解/rethinking-graphql
sonatard
71
11k
Templates, Plugins, & Blocks: Oh My! Creating the theme that thinks of everything
marktimemedia
31
2.4k
Exploring the Power of Turbo Streams & Action Cable | RailsConf2023
kevinliebholz
34
5.9k
Transcript
Rustがどんな言語なのか説明する時に 考えたこと Igaguri Rust Kansai Meetup #5
「趣味でRust書いてます」というとありがちなこと Q. 「Rustってどんな言語なん?」 • 答え方には色々ある ◦ コードを見せる ◦ 性質や機能を列挙する ▪
所有権とかがあって、静的型付けで、ネイティブバイナリにコンパイルできて、 …… ◦ どんな所で使われているか ▪ MozillaでFirefoxのレンダリングエンジンの Servoを記述するのに使われている ◦ どんな意図で作られたのか ▪ →本日のメイン
Rustの設計目標(1/4) • https://prev.rust-lang.org/en-US/faq.html のQ&Aに設計目標が掲載されている。 (Rustプロジェクトの目標は)安全であり、並行性をサポートし、実用的なシステムプログラミング言語を設計・実装することである。 Rustが存 在している(作られた)のは、他のプログラミング言語の抽象化と効率性の(両立の)水準が満足できるものではないからである。 特に、 1. 安全性についてあまり考慮されていない
2. 並行性に関するサポートが貧弱 3. 使い方が自然にはわかりにくい 4. リソースを制御する手段があまり提供されていない などの問題点がある。 Rustは上記の問題点を改善して効率的なコードと使いやすい抽象化を両立した選択肢として存在している(作られている)。
Rustの設計目標(2/4) • 想定される使用場面 ◦ (ネットワーク越しに)攻撃者からの攻撃を受けうる、 CPU-boundなソフトウェア ▪ Webブラウザ、画像変換ツール、ゲーム ▪ インターネットに接続される組み込みソフトウェア
• なぜ安全性が必要なのか ◦ インターネットの荒野ではソフトウェアの脆弱性はほぼ確実に犯罪者に利用されるから ▪ 乗っ取り・情報漏洩・ボットネット ◦ 特にメモリ安全性は、破られた時にメモリ内容の漏洩や任意コード実行につながる • なぜ高速性が必要なのか ◦ 早く結果を返すため ◦ リソースを節約するため ◦ 電力を節約するため
Rustの設計目標(3/4) • 既存言語と比べる ◦ 高速性はあるが安全性が不足している言語 ▪ C, C++, アセンブリ ◦
安全性はあるが高速性が不足している言語 ▪ GCを採用するほとんど全ての言語 • Java, C#, Haskell, Go, ……
(補足)具体的なプログラミング言語間の速度差 https://benchmarksgame-team.pages.debian.net/benchmarksgame/which-programs-are-fastest.html CPU-boundなベンチマークの結果が集計されている(対数グラフに注意)
Rustの設計目標(4/4) • 高速性 ↔ 安全性 というトレードオフ ◦ プログラマによるメモリ管理による高速性。安全性について妥協する。 ◦ 実行時にGCを使うことによるメモリ安全性。高速性について妥協する。 •
Rustは高速性と安全性を両立する ◦ 高速性 ↔ 安全性 ↔ 学習コスト という3点間のトレードオフに変形 ▪ 高速性と安全性を取り、学習コストについて妥協する Rustがどのように高速性と安全性を両立しており、そのために新たに何を学ばなければ ならないかということが、Rustの特徴の説明になる
(例) 型チェック戦略 (1/2) • C/C++ ◦ 弱い静的型付け ▪ 型システムは安全性を網羅的に保証せず、未定義動作になるパターンが数多く存在 ◦
(C++) 仮想関数はオプション ▪ 継承による多相性を使わないなら、仮想関数テーブルを経由しないので速い • Java ◦ 強い静的型付け + ダウンキャスト等の実行時チェック ▪ 不正なダウンキャストは例外を出すので、未定義動作にはならない ◦ メソッド呼び出しはデフォルトで動的ディスパッチ ▪ 継承のサポートのために必要 ▪ 不要な場合JITで消去される(が、JIT自体に実行時コストがかかる) • Ruby ◦ 実行時に型タグを検査(いわゆる「動的型付け」) ◦ インスタンス変数もメソッドもテーブル上にある
(例) 型チェック戦略 (2/2) • Rust ◦ 強い静的型付け ▪ コンパイル時に使われている値の型の整合性を保証 ▪
実行時チェックが不要なので高速 ◦ 継承がない ▪ ないので仮想関数テーブルを用意しなくていい ▪ 動的ディスパッチが欲しければトレイトオブジェクトを使用する • Box<dyn T>などに仮想関数テーブルが含まれている
(例) 所有権, 借用, ライフタイム (1/2) • 問題: Double-Free、Use-After-Free等のメモリ管理系の脆弱性 • CやC++での扱い
◦ 変数はスタックとヒープの両方に確保できる ▪ 関数内でしか使わないなら、スタックに置くほうが高速なので嬉しい ◦ プログラマがmalloc / freeを使って管理する ▪ ミスは良くてメモリリーク、悪いと未定義動作を引き起こす ◦ C++には限定的に解決するスマートポインタが存在 • JavaやRubyなどでの扱い ◦ クラスのインスタンスは全て参照経由で扱う ◦ 参照型の参照先になるインスタンスは全てヒープに確保 ◦ プログラムは参照を使い終わったらそのままポイ捨て ◦ GC機構が実行中に参照の有効無効を判定してメモリを回収する ▪ 様々な工夫があるが、それでも実行時コストがかかる
(例) 所有権, 借用, ライフタイム (2/2) • Rustの扱い ◦ 所有権 (ownership)
▪ 値には単一の所有者が存在する ▪ 所有者は自身が開放される時、所有する値を開放する 管理責任を持つ ◦ 借用 (borrowing) ▪ 所有者以外は限定的な操作のみが許され、 freeなどはできない ▪ 可変参照と共有参照の区別がないと、 Use-Afer-Freeを起こせる • Vecの要素への共有参照がある状態で Vecを拡大した場合など ▪ 循環参照を作らせない効果もある ◦ ライフタイム (lifetime) ▪ 借用である参照の期間をチェックする ▪ Use-After-Freeを回避 ownership
(例) 静的に解決されるジェネリクス (1/2) • C ◦ そんなものはない • C++ ◦
コンパイル時に具体的な型のそれぞれについて展開されるテンプレート ▪ 具体的な型が埋め込まれたコードになり、最適化が効きやすく高速 ▪ 型の保証は不十分(展開後のコードが不正な時はコンパイルエラーにはなる) • Java ◦ 具体的な型(メソッド実装)が動的に解決されるジェネリクス ▪ Javaのジェネリクスは型検査後に型消去され Objectクラス扱いになる ▪ インスタンスを使う時は自動的にダウンキャストをして使用 ▪ プリミティブ型が使えないのはこの機構のせい • Ruby ◦ ダックタイピングなのでそもそもジェネリクス機構という概念が存在しない ▪ 実行時にインスタンス変数やメソッドの有無を判定している(遅い)
(例) 静的に解決されるジェネリクス (2/2) • Rust ◦ コンパイル時に具体的な型のそれぞれについて展開されるジェネリクス ▪ C++と同じく、通常のコードに展開されるため最適化が効きやすい ▪
C++と同じく、(T: Sizedなら)スタックに確保できるので速度性能が良い ◦ トレイトを使用して型の範囲を制限できる ▪ 展開前に型エラーを出せるため、エラーメッセージが人間に優しくなる ▪ T::default() のようにトレイトにあるメソッドではない関数も呼び出せる
まとめ & 余談 • まとめ ◦ 設計目標の観点から Rustの特徴を説明するアプローチがある ▪ 高速性と安全性を両立し、そのために導入した機構に関する学習コストを犠牲にしている
◦ Rustの基本的な仕様は、設計目標を達成するように選ばれている ▪ 型、所有権・借用・ライフタイム、ジェネリクスの仕様、継承の排除 …… • Rustの仕様をきちんと理解するには、コンピュータに対する理解が必要 ◦ なぜデータをスタックに置くほうが好ましいのか ▪ ヒープメモリの確保のコスト、キャッシュメモリの動作等 ◦ なぜ動的ディスパッチがあると遅いのか ▪ 仮想関数テーブルの動作原理