unsafe を「危険な記法」から「守るべき契約」に進化させる話unsafe の意味を、単なる「危ない構文」から「呼び出し側にも責任がある契約」へと再設計しているunsafe な処理を 内側の unsafe { } ブロック に閉じ込め、コンパイラが見える形で明示するunsafe は、ポインタそのものよりも メモリ安全性に関わる契約 を表す方向に広がる/// <safety> コメントを推奨し、レビューしやすくするMicrosoft の .NET Blog で、C# のメモリ安全性を大きく改善する構想が紹介されました。
ざっくり言うと、**unsafe キーワードの意味を作り直す** という話です。
これまでの unsafe は、ポインタを使うための「危ないモード」のようなものでした。もちろんそれでも十分に意味はあったのですが、今回の変更はもっと踏み込んでいます。
unsafe を「このコードは危ないかもしれない」ではなく、「ここには安全性について、呼び出し側と実装側の契約がある」 という形で扱おうとしているんですね。
この発想、かなり面白いと思いました。
危険なコードを完全に禁止するのではなく、危険を見える化して、レビューできるようにする。現実的で、しかも今の時代に合っています。
C# は普通に書く分にはかなり安全です。
たとえば:
IndexOutOfRangeException になるnull まわりも言語とランタイムが守ってくれるつまり、ふつうの C# は「危ないことが起きにくい」設計 なんです。
でも、unsafe を使うと話が変わります。
ここでの unsafe は、ざっくり言えば コンパイラやランタイムが全部は守ってくれない領域 に入る、ということです。
Microsoft の説明では、unsafe code が必要になる理由は主に2つ。
これは現実的です。
OS や既存ライブラリとの接続、あるいは低レベル最適化では、こういう領域がどうしても必要になります。完全に消すのは無理、だからこそ 扱い方を厳密にする のが今回のテーマです。
unsafe は「構文」ではなく「契約」になるここが一番重要です。
従来の unsafe は、どちらかというと「ポインタを使えるようにするためのスイッチ」でした。
しかし新しいモデルでは、unsafe は 安全性に関する責任が呼び出しグラフを通じて伝播する印 になります。
つまり、
が、コード上で見えるようになるわけです。
個人的には、これはかなり筋がいいと思います。
危険なコードの怖さって、「危ない」こと自体より、どこまでが安全でどこからが自己責任なのか分かりにくい ことにあるので。
そこを言語レベルで線引きしようとしているのは、かなり賢いです。
記事では、unsafe の扱いを次のような層で説明しています。
unsafe { } ブロック危険な操作は、まず 内側の unsafe { } ブロック に閉じ込める必要があります。
ここでの危険な操作には、たとえば:
*ptr のように中身を見ること)が含まれます。
要するに、
「ここから先は危ない処理です」とコード上で囲う 形です。
これ、地味ですがかなり大事です。
危険な処理が散らばるとレビュー不能になるので、まず 危ない部分を局所化する。これはソフトウェア設計の基本としても気持ちいいですね。
もしメソッドの内部で unsafe な処理を使っていて、その責任を呼び出し側にも伝えたいなら、そのメソッド自体を unsafe として宣言 します。
すると、そのメソッドを呼ぶ側にも「この呼び出しには安全性上の注意が必要です」という情報が伝わります。
つまり、unsafe は単発の印ではなく、呼び出しチェーンを通じて広がる契約 になるわけです。
これは Rust や Swift に近い方向だと記事は説明しています。
C# もついに、より厳密で伝播型の unsafe に寄っていく、という感じです。
/// <safety> コメントunsafe member には、**/// <safety> ブロック** で契約を書くことが強く推奨されます。
これは「このメソッドを安全に使うには、呼び出し側が何を保証すべきか」を説明する文書です。
たとえば:
size バイト有効でなければいけないといった内容が入るイメージです。
これがあると何が良いか。
レビューできる んです。
暗黙の「たぶん大丈夫」ではなく、明文化された「ここを満たせば安全」という話になる。
私はこれ、かなり実務向きだと思います。AI がコードを書く時代ならなおさら、コメントは飾りではなく 安全性の契約書 になっていくはずです。
あるメソッドの中に unsafe ブロックがあっても、そのメソッド自身を unsafe にしない場合があります。
このとき、そのメソッドは unsafe と safe の境界 になります。
ここで必要なのは、unsafe 側の責務をちゃんと「引き受けて解消する」ことです。
つまり、呼び出し側に危険を押し付けずに済むよう、次のどれかで保証する必要があります。
たとえば malloc が「返したポインタは少なくとも size bytes 有効」という保証を持つなら、それを前提として安全側に戻す、という考え方です。
この「境界で責任を解消する」という見方は、かなり実務的です。
unsafe を単に増やすのではなく、どこで安全に戻すか を設計の中心に置いているのがいいですね。
C# 1.0 の unsafe は、主に「ポインタ関連の機能を使えるようにする」ためのものでした。
たとえば:
stackallocsizeof の一部の使い方今回の変更では、これがもっと厳密になります。
unsafe を type modifier として使うのはエラーになるunsafe は class 全体ではなく、method / property / field など、より細かい単位 に移るunsafe は使えないnew() の generic constraint は、safe な parameterless constructor のみを対象にするsafe という新しいキーワードが導入されるunsafe は、もう自動で unsafe context を作らない最後の点は地味に大きいです。
今後は、ポインタ型があるだけではなく、そのポインタをどう扱うか が重要になります。
要するに、「型が怖い」ではなく「操作が怖い」に寄せているんですね。
IntPtr ではなく typed pointers を勧めているのも面白い記事では、新しいコードでは IntPtr より byte* のような typed pointer を勧めています。
本当に opaque(中身を知らない)なポインタなら void* を使う、という話も出ています。
さらに、既存の IntPtr ベース API には、必要なら:
IntPtr 版を hidden / soft-obsolete にするという方向も示されています。
このあたり、かなり実践的です。
IntPtr は便利ですが、何でも入るぶん意味がぼやけやすい。
typed pointer のほうが「これは何のポインタか」がわかるので、レビューもしやすいはずです。
この記事で特に印象的だったのが、AI-assisted code generation への言及です。
コード生成が速くなると、ソフトウェアの生産量は増えます。
でも人間のレビュー速度は、そんなに急には上がりません。
すると何が起きるかというと、
という問題が出てきます。
だからこそ、unsafe を 見える契約 にしておく必要がある、というのが Microsoft の主張です。
これは単なる言語デザインの話ではなく、AI 時代の開発体制の話 でもあります。
私はここにかなり現代性を感じました。
これからの言語機能は、「人間が上手に書くため」だけじゃなく、機械が生成したコードを人間が監査しやすくするため にも設計されるんだろうな、と思います。
記事によると、この新しいモデルと構文は:
の予定です。
また、最初は opt-in、つまり自分で有効化する形式になります。
そして将来的には、Nullable Reference Types のようにテンプレートが新モデルを有効にする方向へ進むかもしれない、という説明でした。
つまり、すぐに世界がひっくり返るわけではないけれど、
ゆっくり、でも確実に新しい標準へ移行していく 流れです。
この変更、地味に見えてかなり大きいです。
unsafe は昔から「必要だけど危ないもの」でした。
でも危ないものを危ないまま放置すると、結局はレビュー不能になります。
今回の設計はそこをちゃんと踏み込んでいて、危険を構文ではなく責任の流れとして扱う のが本質だと思います。
特にいいのは、unsafe を「特別な呪文」ではなく、
“誰が何を保証するのか” を明文化する仕組み に変えようとしている点です。
もちろん、これで unsafe が魔法のように安全になるわけではありません。
むしろ逆で、unsafe を書く難しさはそのまま残る はずです。
でも、その難しさを隠さず、レビュー可能な形に整える。そこがすごく誠実だと思いました。
C# の新しい memory safety モデルは、unsafe を単なる「危険な構文」から、安全性の契約を明示する仕組み へと進化させます。
unsafe { } ブロック、契約の伝播、/// <safety> コメント、境界での責務解消といった仕組みで、危険なコードを見える化するのが狙いです。
AI によるコード生成が当たり前になっていく中で、これはかなり重要な方向転換だと思います。
「書けること」より「レビューできること」を重視する。
C# はそこに向かって、かなり本気で舵を切っているように見えます。