Structural Analysis 5

型とPython——なぜAIネイティブ言語の中心になったか

C#は技術的に優れているが、AIネイティブ基層を素直に扱えない。これは中途半端な言語の構造的帰結である。

型の歴史——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ネイティブ基層は形が事前に決まらない世界である:

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#を使っている場所を点検すると:

  1. 既存のMicrosoftエンタープライズ——20年前の.NET Framework資産を持つ大企業
  2. Unityゲーム開発——ゲームエンジンがC#採用のため、選択肢なし
  3. 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時代の言語選択:
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を書かせれば良い。
中途半端な言語に時間を投じる理由は、もう無い。

次章では、この「型の貧弱さ」が社会的にどんな帰結を生んだかを見る。なぜソフトウェア開発に大量の人が必要だったのか——その本当の理由を明らかにする。

← 前: AI革命の正体——二層同時の変化 次: 翻訳労働の発見——大量の人が要った本当の理由 →

言語選びは、AIネイティブな仕事の入り口である。

Pythonを選ぶことは、AIネイティブ基層を素直に扱える唯一の選択である。中途半端な言語に時間を投じない。

AISeed — 生物多様性・食料・AIと暮らし(Facebook)