今日は using alias の話。

これはちらほら実装が始まっているので近々触れるものが出てくるんじゃないでしょうか。

既存の using ディレクティブ

using alias は、using ディレクティブを書くときに using T = System.DateOnly; みたいに書いて、以後は T だけで型名を参照できるやつ。 現状何が問題かというと…

まず、以下のコードであれば現状でもコンパイルできるんですが…

using List = System.Collections.Generic.List<int>;
using ListA = System.Collections.Generic.List<int[]>;
using ListN = System.Collections.Generic.List<int?>;
using ListT = System.Collections.Generic.List<(int, int)>;

そのくせ以下のコードはコンパイルできません。

using Primitive =  int;
using Array = int[];
using Nullable = int?;
using Tuple = (int, int);

要するに、ジェネリック型引数なら制限がほとんどないのに、トップレベルの時にだけ、以下のものを書けないという制限がありました。

  • int みたいにキーワードを使ったプリミティブ型 (⇔ System.Int32 なら書ける)
  • null 許容型 (T?) (⇔ System.Nullable<T> なら書ける)
  • タプル ((T1, T2)) (⇔ System.ValueTuple<T1, T2> なら書ける)
  • 配列 (T[])

まあさすがにいい加減これを認めようという話になっています。

一番需要があるのはタプルですかね。 あと、最近では関数ポインターなんかも delegate*<int, int, void> みたいな感じで名前が長くなりがちなので、これに対しても使いたいみたいです。

微修正

int とか int? とかに対応するだけなら大した変更は要らないみたいです。 構文的には1行書き変わるだけ

using_alias_directive
-    : 'using' identifier '=' namespace_or_type_name ';'
+    : 'using' identifier '=' (namespace_name | type) ';'
    ;

たぶん、「元々 using 専用に特殊処理していたけども、普通の型名参照と同じものに置き換える」みたいな感じでしょうか。

これは… もっと早くから対応してくれててもよかった疑惑が…

トップレベルの null 許容参照型

参照型に対しては、トップレベルでは ? をつけれないようにするみたいです。 まあ、今でも、typeof(string) は書けても typeof(string?) とは書けないので、 それと同じです。

using List = System.Collections.Generic.List<string?>; // これは OK。
using S = string?; // これはダメ。

ポインター

要望として関数ポインターのエイリアスを作りたいわけですが。 unsafe なものを単に using T = int*; とか書いていいのかどうかという議題がありました。

これに対しては結局、using unsafe という構文を導入するみたいです。

using unsafe T = int*;
using unsafe F = delegate*<int, int, void>;

今後の課題: 型引数

エイリアスをジェネリックにして型引数を持たせたいという話もあります。 以下のような、エイリアスの右辺にも <T> を付けたいというやつ。

using List<T> = System.Collections.Generic.List<T>;

これはこれで要望はあって、Backlog (すぐに手を付けるほどの優先度にはない)とはいえ、 Champion (C# チームの担当がついてる状態)にはなっています。

ただ、これの対応は「微修正」では済まないので、 C# 12 マイルストーンからは外れるみたいです。