AIの時代だからこそ、型システムがより厳格な静的型付け言語(GoやRustなど)が良いのでは?という話
はじめに
CursorのようなAIのコードエディタがめちゃくちゃ進化してきている、こんな時代だからこそ静的型付け言語、特に厳格な静的型付け言語であるRustとの相性が良いのでは?という話をポエム的に書いてみます。
この記事ではあえてRustに特化して比較や検討をしているのは、個人的な好みの問題です笑
今の現場では静的型付け言語であるTypeScriptを使っているけど、厳格な静的型付け言語ではないし、実装されているコードも現場や人によって異なることが多くて、AIと共創していくことを考えたときにベターな言語があるんじゃないかって思ってつらつら書いてみます。
(TypeScriptって本当に十人十色なコードができてしまうから悩ましいw)
一方で、TypeScriptは型安全じゃないからすばらしいという意見もあるので、あくまでポエム的な内容であるということはご理解ください。
TypeScriptにおけるお困りごと
- ある程度、自由度が許容されているTypeScriptだとAIが生成するコードが毎回異なる(ことがある)
- TypeScriptの型システムはJavaScriptとの互換性を保つため、型の厳密さが犠牲になる場合がある
- そのため、AIにはしっかり指示をしないと、想定をしているコードが生成されないことがある
- 実行時にエラーになるコードが生成されることがあるため、生成されたコードが実際に動くかは不明である
- これを防ぐためには、生成されたコードには必ずテストを含めるよう指示をして、テストで動作確認を行う必要がある
例えば、以下のような指示をすると、出来上がるコードは3パターン存在します。
ユーザーを処理する関数を作成してください。
ユーザーはIDと名前を持ち、名前を大文字に変換して返す機能が必要です。
interface User {
id: number;
name: any; // 型の指定が曖昧
}
function processUser(user: User) {
return user.name.toUpperCase();
}
interface User {
id: number;
name?: string; // オプショナルプロパティ
}
function processUser(user: User) {
return user.name.toUpperCase(); // nameがundefinedの場合を考慮していない
}
interface User {
id: number;
name: string;
}
function processUser(user: User): string {
return user.name.toUpperCase();
}
さらに、型の曖昧なコードや部分的な型指定の場合、実行時にはJavaScriptとして動作するため、実行時にエラーになる可能性もあります。
interface User {
id: number;
name?: string;
}
function processUser(user: User) {
return user.name.toUpperCase(); // AIがnullチェックを省略
}
const user = { id: 1 }; // nameがundefined
console.log(processUser(user)); // TypeError: Cannot read properties of undefined
実際に、上記のようなコードがCursorなどで出来上がるかというとそんなことはありません。
なぜなら、tsconfig.json
で厳密な設定(例: "strict": true
など)を有効にしていれば、生成するコードで上記のような問題があった場合には、コンパイルエラーとなるので検知することは可能です。
ただし、一発目から上記のようなコードが生成されるというよりは「すみません、nullチェックが足りてませんでした。修正します。」みたいなやり取りを行った後、修正されることが多いです。
(これを考えると、コード生成の効率も少し良くない言語なのかもしれないですね)
つまり、TypeScriptでコードを生成させる前に、tsconfig.json
で厳密な設定をしっかり行っておく必要があるということです。
ただし、既存のリポジトリに導入するとなると、厳密な設定を導入できていない可能性もあるので、そうなると、指示ベースで上記のようなコードが生成されないように指示をする必要があります(もしくは、Project Rulesなどで明記する必要がある)
これで一件落着かというとそうではなく、AIが複数のパターンを生成してしまうケースはまだあります。
例えば、以下のような実装です。
interface User {
id: number;
name: string;
}
function processUser(user: User): string {
return user.name.toUpperCase();
}
type User = {
id: number;
name: string;
};
function processUser(user: User): string {
return user.name.toUpperCase();
}
class User {
constructor(public id: number, public name: string) {}
}
function processUser(user: User): string {
return user.name.toUpperCase();
}
上記で実現しようとしているコードの内容はほとんど同じですが、受け取ろうとしている型がそれぞれ違います。これらを統一されたルールで生成するようにするためには、指示ベースかProject Rulesで情報を与える必要があります。
これ以外にも、エラーハンドリングの有無であったり、ユニオン型やResult型の使用などなどを考えると、AIに伝えないといけないコンテキストは盛りだくさんになっていきます。
こういったことを考えていくと AIの時代にはもっと厳格な静的型付け言語でかつ、限られた実装パターンしか存在しない言語が良いのでは? と考えています。
Rustが採用される理由
ではまず、Rustが採用される理由をAIに聞いてみます。
※ Grokの回答です
-
メモリ安全性と信頼性
- メモリ安全性(メモリ関連のバグの発生を防ぐ)をコンパイル時に保証すること
- 所有権(Ownership)と借用(Borrowing)の仕組みを利用して、メモリ関連のバグをコンパイル段階で検出
-
C/C++並の高パフォーマンス
- 「ゼロコスト抽象化」という概念を掲げており、CやC++と同等の実行速度を実現
-
開発者体験と生産性
- モダンなツールチェーン(Cargo、rust-analyzer)とエラーメッセージの親切さで、開発体験が良い
- 型システムやパターンマッチングも、コードの可読性と保守性を高める
-
エコシステムと多用途性
- WebAssembly、CLIツール、ネットワークプログラミング、OS開発、ブロックチェーンまで幅広い用途で使える
- crates.ioのエコシステムも充実してる
-
コミュニティと業界の後押し
- コミュニティも活発で、学習リソースやオープンソースプロジェクトが豊富
-
安全性とパフォーマンスのトレードオフがない
- 他の言語だと、安全性かパフォーマンスのどちらかを犠牲にしがち
- でも、Rustは両方を兼ね備えてる
シンプルにRustの採用理由を聞いてみても、AIや他の言語との比較は基本的に言及されません。
それはそうだと思いますが、
今後はもしかしたらAIとの相性について言及される可能性もあるかもしれません。
Rustの導入を懸念する理由
今度はRustを導入する懸念をAIに聞いてみましょう。
※ Grokの回答です
-
学習曲線の急峻さ
- Rustの所有権モデル、借用チェッカー、ライフタイムといった概念は、開発者にとって馴染みがなく、習得に時間がかかる
-
初期開発速度の低下
- Rustの厳格なコンパイラは安全性のために細かくチェックするため、コードを書く→コンパイル→エラー修正のサイクルが最初は長く感じる
-
エコシステムの成熟度のばらつき
- Rustのエコシステム(crates.io)は急速に成長しているが、他のメジャーな言語に比べるとライブラリの数や成熟度がまだ劣る
-
人材採用とチームスキル
- Rustの開発者は需要に対して供給が少なく、採用が難しい
- 全員をRustにリスキルするのは時間もコストもかかる
-
ビルド時間と開発環境のセットアップ
- Rustのコンパイル時間は、C++より速い場合もあるが、Goに比べると遅い
- 特に、大規模プロジェクトや依存クレートが多い場合、ビルドがボトルネックになる
- また、Rustのツールチェーン(rustup, Cargo)のセットアップが、初心者には面倒に感じることもあるかもしれない
言われてみれば、その通りだなとは思います。
ただ、AIの活用でいくつか懸念点は払拭されるかなとか思ったりもします。
例えば、「学習曲線の急峻さ」「初期開発速度の低下」「人材採用とチームスキル」はAIによって代替できる部分はあると思います。
AIがある程度コードを実装してくれる分、学習コストは落ちるのかなと思います。今までは、まだ身に付いていない言語だとわざわざ言語仕様をググったりしながら開発をする必要がありましたが、現代ではAIと対話しながら実装が可能です。
(こんな時代だからこそ、AIが実装したコードが正しいか判断できるようになるために、言語仕様をきちんと理解しておくということが求められそうですね)
また、初期開発速度もコードを書く→コンパイル→エラー修正のサイクルをAIが対応してくれると考えれば、このコストもほぼない状態になるかなと思います。
さらに、「人材採用とチームスキル」はAIが開発者の代わりに担ってくれると考えれば、リソースはAIが埋めてくれるし、開発者は実装よりも学習や設計にコストをかけられるようになれば、リスキリングもそこまでコストにならないのではないかと思います。
正直、「ビルド時間と開発環境のセットアップ」に関しても開発者の手を使わなくて済むのならそこまでコストにはならないかなと思いつつ、確かにコンパイル時間の遅延は実際の動作確認を行うまでのコストにはつながるので、ここは一定の懸念は残るかなと思います。
(TypeScriptもコンパイルがそこまで高速ではないかもですが、"Project Corsa"が上手くいったらここはTypeScriptの強みとなるかもしれないですね)
AIとRustの相性が良いと思う理由
今度はAIにRustとの相性が良いと思う理由を聞いてみます。
※ Grokの回答です
-
Rustの厳格な型システムとAIのコード生成の補完性
- Rustは静的型付けと所有権モデルにより、コンパイル時にエラーをガッチリ検出してくれる
- AIは大量のコードを素早く生成できるけど、細かい文脈や型エラーを完璧にケアするのはまだ難しい
- Rustのコンパイラが適切に教えてくれるから、AIが生成したコードのデバッグや修正が楽になる
- 所有権エラーや型ミスマッチをコンパイラが明確に指摘してくれて、AIの提案を効率的にブラッシュアップできる
-
Cursorのコンテキスト理解力とRustのプロジェクト構造
- プロジェクト全体のコードベースをインデックス化して、コンテキストを把握しながらコードを生成・補完できる
- Rustのプロジェクトは通常、明確なモジュール構造(
Cargo.toml
やsrc/
配下のファイル構成)を持つため、Cursorが「どのファイルに何を書くべきか」を理解しやすい - 特に
.cursorrules
やProject Rules
を使って、Rustプロジェクトのコーディング規約やディレクトリ構成をAIに教え込むと、生成コードの精度が上がる
-
生産性と安全性の両立
- Rustはメモリ安全性やパフォーマンスを重視する言語だが、学習コストが高い
- CursorのようなAIエージェントを使えば、Rustの複雑なシンタックス(ライフタイムや借用とか)をAIが補完できる
- たとえば、CursorのAgentモードでRustのボイラープレートを生成してもらえば、開発者はビジネスロジックに集中できる
まだ、RustとAIのコードエディタの相性を確かめられていないからなんとも言えないが、上記で挙げられていることはなんとなく納得もできる。
Rustのような厳格な型システムがあれば、AIの雑さをカバーするセーフティネットにもなりそうだなぁって感覚はある。
Rustのコンパイラが適切に教えてくれるというと、人間的にはそうでもないかもしれないが、AIが読み取りやすい用にエラーは出してくれている感覚はある。型が厳格である分、TypeScript等で拾えなかったコンパイルエラーも拾えるようになる。
また、生産性と安全性の両立が叶うなら、素晴らしいことだと思う。
生産性や開発速度を優先するからこそ、TypeScriptであったり、RubyやPHPのような動的型付け言語を採用しているところはある。だけど、AIのコードエディタの登場によって、ここは大きく変わっていきそうな予感もしている。
特に、Rustの学習コストとして挙げられがちな「所有権モデル、借用チェッカー、ライフタイム」などの概念をAIが補完しながら実装できるなら、今までにない開発者体験になると思っている。
とはいえ、複雑なロジックがあったりすると、修正ループにハマったりする可能性はあるので、言語問わず、タスクを小さく分割して指示を明確にするというのは忘れてはいけないですね。
おわりに
RustはAIインフラだったりWebAssemblyで注目されてるし、AIのコードエディタは生成AIの進化とともにどんどん賢くなっている。これからAIエージェントがもっと長期記憶やデバッグ能力を獲得したら、Rustのような言語の開発はさらに革命的になるんじゃないかなぁと期待しています笑
(こんな記事を普段書かないので、おわりが少し気持ち悪くてごめんなさいw)
Discussion
実際に現時点でAIにRustを書かせてみてどうだったのか、っていうのも知りたいです!
偏見ですが、学習元になるコードも少なくて、ライブラリも頻繁に開発されていてインターフェイスが安定していない、というイメージがあるので、コンパイル通るコードを出力する確率が低くなって一生修正を繰り返しそうな気がします。
あとは、AIは意味的にコードを理解しないので、コンパイルを通すためだけに、ライフサイクルのスコープを無駄に広めにとったり、借用を避けて無駄に値をコピーしたり、っていうズルをしてきそうな気も。
コメントありがとうございます!
これはこれからいろいろと試していこうかなと思っているので、試してみながら何か発見があれば、また記事を書こうと思います!
これは今のところの肌感ですが、TypeScriptよりはコード生成の精度が高いかなぁっていう感覚はあります。
メジャーなライブラリ(tokio, serde, sqlxなど)であれば、今のところ不便なく使えてはいますね!
これは一定発生したりはあるかもです。
コンパイルを通すのに借用を避けて無駄に値をコピーしようとしているのは感じますが、人間も同じようにやってしまうところもあるので、なんとも言い難いですね笑
上記含めて、AIがあるからといって言語理解が不要ということはなく、むしろ、AIが実装したコードが正しいか判断できるようになるために、言語仕様をきちんと理解しておかないといけないなぁとより感じています!
実際に3つのモデルに聞いてみました。
llama-4
perplexity
OpenAI o3
idの型の違いや、メソッドを定義するか関数を定義するかという違いはあれど、TypeScriptほどの種類は出なさそうと感じました。
AIが生成したコードを型の方からもテストできるので、品質はRustのほうがいいと感じる場面が多かったです