型の歴史——4段階の進化
前章で「プログラミング言語の型が拡張された」と書いた。この章では、その歴史と構造的意味を詳しく見る。
プログラミング言語が扱える「型」は、半世紀をかけて4段階で進化した。
| 段階 | 扱える型 | 代表言語 | 時代 |
|---|---|---|---|
| 1. 機械語 | bit, byte, word | アセンブリ、初期Fortran | 〜1960s |
| 2. 構造体 | int, float, char, struct, array | C、Pascal | 1970s〜80s |
| 3. オブジェクト | + class、interface、generics | C++、Java、C# | 1990s〜2010s |
| 4. AIネイティブ基層 | + Markdown、DataFrame、JSON、Parquet、RDB、HTML、embedding | Python(特にAI連携) | 2020s〜 |
各段階の移行は、前段階の限界が見えた時に起きた:
- 段階1→2:機械語では人間が大規模プログラムを管理できなくなった
- 段階2→3:構造体では業務の概念(顧客、注文、請求)をモデル化できなくなった
- 段階3→4:オブジェクトでは形が事前に決まらないデータを素直に扱えなくなった
Java/C#は段階3で止まった
Java/C#は段階3の頂点として設計された言語だ。事前にクラス定義を書いて、そこにデータを流し込む——という世界観で出来ている。
段階3の言語の前提: データを扱う前に、データの形をクラスとして宣言せよ。 強い型付け、コンパイル時検査、リファクタリング支援、IDE補完——全部この前提に乗っている。
この前提は、業務システムの開発には合理的だった。顧客テーブルの形は事前に決まっている。注文の構造も決まっている。CRUDアプリは、事前にスキーマを宣言できる世界だった。
しかし、AIネイティブ基層は形が事前に決まらない世界である:
Markdown → 本文構造はAST動的、文書ごとに違う
DataFrame → 列構成はデータ次第
JSON → フィールドが省略・追加される
Parquet → 型は持つが構成は流動的
RDB → JOIN結果の形は問い合わせ次第
HTML → DOMは事前に決まらない
embedding → 次元数や意味は学習結果次第
全部、触る前に形が決まらないデータだ。クラスベースの言語は、触る前に形を要求する——順序が逆になる。
具体的な impedance mismatch
同じことを両言語で書くと、差が一目瞭然である。
例:JSONから値を取り出す
Python:
data = json.loads(text)
print(data["customer"]["address"]["city"])
C#:
public class Address { public string City { get; set; } }
public class Customer { public Address Address { get; set; } }
public class Root { public Customer Customer { get; set; } }
var data = JsonSerializer.Deserialize<Root>(text);
Console.WriteLine(data.Customer.Address.City);
Pythonはデータの形を知らなくても触れる。C#は触る前にクラス定義を要求する。AI対話の中でこれは決定的な差を生む——AIに「このJSONを見て変換して」と頼んだ時、Pythonは3行で済むが、C#はクラス定義から始まる。
例:YAML設定を読む
Python:
config = yaml.safe_load(open("config.yaml"))
db_url = config["database"]["url"]
C#:
var deserializer = new DeserializerBuilder().Build();
var config = deserializer.Deserialize<MyConfigClass>(reader);
var dbUrl = config.Database.Url;
C#は「YAMLの形をクラスとして先に宣言する」ことを強要する。動的に揺れる設定(多くのYAMLはそう)には根本的に向かない。
例:DataFrame と Parquet
Pythonはpl.read_parquet("file.parquet")一行。C#にはDataFramという中心的な抽象が存在しない。Microsoft.Data.Analysisは公式パッケージとして存在するが、コミュニティで使われていない。Pandasやpolarsとはエコシステムの規模が桁違いに違う。
Pythonの「弱み」が「強み」に逆転した
Pythonは長年、こう批判されてきた:
- 動的型付けで型安全でない
- duck typingで実行時まで型エラーが分からない
- インタプリタで遅い
- GILで真の並列処理ができない
これらの「弱み」が、AI時代に全部「強み」に逆転した**:
| 性質 | 段階3時代の評価 | AIネイティブ時代の評価 |
|---|---|---|
| 動的型付け | 弱み(エラー検出が遅い) | 強み(形が決まらないデータを扱える) |
| duck typing | 弱み(曖昧、保守困難) | 強み(AIの動的出力をそのまま受け取る) |
| 遅い実行 | 弱み(性能不足) | 無関係(裏で全部C/Rustに逃げる) |
| GIL | 弱み(並列処理不能) | 無関係(重い計算は外部ライブラリで並列化) |
「Pythonは遅い」は事実上、嘘になった:
- pandas / polars / NumPy → C / Fortran / Rust の中身
- PyTorch / JAX → C++ / CUDA / XLA
- DuckDB → C++のベクトル化SQL
- uv / ruff / orjson → Rust製
- Numba → JITでC並み
Pythonの本体はAPI、エンジンは全部ネイティブ。これは完成された分業である。
Python + AI生成Rust の最強の組み合わせ
ここがAI時代の鍵だ。Pythonでホットスポットだけ見つけて、AIにRust拡張を書かせる。
# Pythonで書いた処理が遅い
def heavy_calculation(data: list[float]) -> float:
return sum(complicated_formula(x) for x in data)
これをAIに「Rust の PyO3 拡張に書き換えて」と言うと、5分で:
use pyo3::prelude::*;
#[pyfunction]
fn heavy_calculation(data: Vec<f64>) -> f64 {
data.iter().map(|x| complicated_formula(*x)).sum()
}
maturin buildでPythonから呼べる拡張ができる。性能はC並み、開発体験はPythonのまま。
3年前ならこれはRust専門家の仕事だった。今はAIが書く。
C#にはこの「逃げ道」が存在しない。C#でホットスポットを高速化する選択肢は、unsafe コード(安全性が崩れる)、P/Invoke(煩雑)、C++/CLI(Windows限定で廃れている)、AOT(Rust並みにはならない)——どれも中途半端。「フロントは生産的、バックエンドは高速」というクリーンな分業がC#にはない。
C#が「中途半端」である構造的意味
C#は技術的によくできている。それでもAI時代に勝てない理由は、どの軸でも1位を取れないことにある:
| 軸 | 1位 | C#の位置 |
|---|---|---|
| 純粋な性能 | Rust / C++ | 負ける |
| データ・ML生産性 | Python | 大きく負ける |
| Webフロント | TypeScript | 負ける |
| クロスプラット | Python / Go / Rust | 負ける(Linuxで「外様」感) |
| AIとの相性 | Python | 大きく負ける(訓練データ比) |
| GPU・並列 | CUDA / PyTorch | 負ける |
| スクリプト・自動化 | Python / Shell | 負ける |
| エンタープライズ業務 | Java / C# | 互角(ここだけ) |
C#が一位を取れる軸が一つもない。エンタープライズ業務でもJavaと並ぶだけで圧倒はしない。全てで二位以下の言語——これが「中途半端」の構造的意味だ。
歴史的に「中途半端な言語」は淘汰されてきた:Pascal、Delphi、Perl、Scala——新しいパラダイムが来るたびに、汎用中途半端言語が落ちる。AI時代では、その対象がJava/C#になりつつある。
C#が今も生き残る三つの場面——全部path-dependency
C#を使っている場所を点検すると:
- 既存のMicrosoftエンタープライズ——20年前の.NET Framework資産を持つ大企業
- Unityゲーム開発——ゲームエンジンがC#採用のため、選択肢なし
- Windows専用デスクトップ——WPF/WinForms資産
全て「すでにそこにある」事情で、新規選択ではない。新しく言語を選ぶ理由としては、どれも積極的な根拠にならない。
Microsoftが所有する言語、というもう一つの問題
C# / .NET には、技術以前の問題がある——Microsoft所有であることだ。
| C# / .NET | Python | |
|---|---|---|
| 設計を決める組織 | Microsoft | Python Software Foundation(非営利) |
| ロードマップ発表場所 | Microsoft Build, .NET Conf | PEP, python.org |
| 戦略的従属関係 | Azure / Visual Studio / Windows | 無し |
| 「Microsoftが見限ったら?」 | 進化が止まる | 起こり得ない |
C#はオープンソース化されているが、戦略的方向はMicrosoftが握っている。これは「Microsoft製の良い言語」であり、「公共財としての言語」ではない。Wordと.docxの関係に近い構造である。
Microsoftの過去の言語・フレームワーク遍歴を見れば、リスクは明確だ:VBScript→放棄、Silverlight→放棄、WPF→縮小、WinForms→メンテのみ、UWP→静かに整理、Xamarin→MAUIに置換で混乱。Microsoftが戦略転換すると、C#の優先度も変わる。
Pythonは誰の所有物でもないので、ベンダーの気分で進化方向が変わらない。
「捨てる」が正しい判定
2026年に新規プロジェクトで言語を選ぶ時、選択肢は次のように整理できる:
AIネイティブな仕事 → Python(議論の余地なし)
性能が要る部分 → Rust(AIに書かせる)
Webフロント → TypeScript(暫定、後述)
CLIツール → Go か Rust
データ分析 → Python + DuckDB
業務システム新規 → Python + FastAPI
モバイル → Swift / Kotlin
組み込み → Rust / C
C#を選ぶ場面が、構造的に存在しない。Javaも同じ位置にある(中途半端だが、エンタープライズの慣性で残る)。
「捨てる」が正しい判定だ。新規開発でC# / .NETを選ぶ合理的な理由は、もう無い。
この章の結論——言語選びは構造的選択
AIネイティブな仕事に入るには、AIネイティブ基層を素直に扱える言語を選ぶ必要がある。Pythonは唯一それを満たす。C#/JavaはOOPで止まったまま、新しい基層との impedance mismatch が永続的に残る。
これは技術選定の問題ではなく、AI革命の中に立てるかどうかの問題である。中途半端な言語にいる限り、革命は半分しか経験できない。
Pythonが勝ったのは技術的に優れているからではない。
AIネイティブ基層を素直に扱える唯一の言語だからだ。
C#/JavaはOOPで止まり、新しい基層を「触る前にクラス宣言」を強要する。
性能が要る部分はAIにRustを書かせれば良い。
中途半端な言語に時間を投じる理由は、もう無い。
次章では、この「型の貧弱さ」が社会的にどんな帰結を生んだかを見る。なぜソフトウェア開発に大量の人が必要だったのか——その本当の理由を明らかにする。