今日は、新たにChampion (取り組むこと確定) が2件と、面白そうな提案1件。
- Champion: ref local reassignment #933 … ref ローカル変数の再代入
- Champion "Declaration Expressions" #973 … 宣言式
- ValueEnumerator (fast to code and run) #982 … 値型 enumerator
ref ローカル変数の再代入
C# 7.0 で、参照ローカル変数が使えるようになっていましたが、 参照ローカル変数の再代入はできませんでした。
static ref int Max(int[] array)
{
if (array.Length == 0) throw new ArgumentException();
ref var max = ref array[0];
for (var i = 0; i < array.Length; ++i)
{
if (max < array[i])
{
// max = x; だと、array[0] の内容を上書きしちゃうのでダメ
// こう書きたい(C# 7.0 では無理)
ref max = ref array[i];
}
}
return ref max;
}
一方、C# 7.2でつかされる機能として前々から決まっていたものとして、ref-like 型というものがあります。
これまでの .NET では認められていなかった「フィールドとして参照を持てる構造体」を認めるための仕様です。
その手の構造体を安全に使うにはref
(参照引数、参照ローカル変数、参照戻り値)と同じようなフロー解析が必要で、
その仕様が C# 7.2 で追加されます。
で、C# 7.2のref-like型では、変数への「参照の再代入」を認めている(認められるようにフロー解析を賢く実装した)ので、 だったら、C# 7.0までの参照ローカル変数でも再代入を認められるはず。 ということで、これもC# 7.2で実装しようという流れになっています。
宣言式
こちらは C# 6.0 の頃から提案に上がっていたもの。 以下のように、式の途中で変数宣言ができるという機能。
var square = (var x = int.Parse(Console.ReadLine()) * x;
「パターンマッチと併せて練り直したい」、「パターンマッチ同様、変数x
のスコープをどうするかちょっと迷う」、「大変な割には需要は低め(やらないとは言わないけど優先度低)」みたいな状態だったものに、ついに「Chanpion」タグが付きました。
まあ、ただし、マイルストーンが決まっていないので相変わらず優先度低めです。
値型 enumerator
今の仕様だと、イテレーターを以下のように書きます。
static IEnumerable<int> X()
{
yield return 1;
yield return 2;
yield return 3;
}
これで何が問題かというと、必ずインターフェイスを介して列挙子を返すことになるので、 ヒープ確保が避けれないという点です。
で、この問題を避けるために、結局、イテレーター構文は使わず、構造体な列挙子を1つ1つ作ったりするというつらい最適化作業が待っていたりします。
まあ昔からですが、List<T>
のGetEnumerator
なんかがそういう実装になっています。
書きやすさとパフォーマンスのトレードオフは常にあるものなのでしょうがないと言えばしょうがないんですが、 やっぱり最初から「構造体を生成してくれるイテレーターが欲しい」という提案が出てきたという状態。