Mads、怒涛のClose祭り。

久しぶりに、C# Design Notesが投稿されてました。というか、5月のNotesが今投稿されているなど。 要するに、Visual Studio 2015関連作業がやっと落ち着いたってことなんですかね、きっと。

C# Language Design Review, Apr 22, 2015 #3910

https://github.com/dotnet/roslyn/issues/3910

式ツリー

式ツリー化できる構文とできない構文の差が大きくなりすぎてる。 全部考えると非常に労力がかかって、その努力に見合うと思えない。

ただ、?. と string interpolation に関しては、新しいノードを導入しなくてもできそう。それくらいは考えてもよさそう。

nullable 参照型

互換性問題があるので、以下の2つのアプローチが考えられる。

  • two-type: 既存のTの意味を変えて、これを非nullにする。nullableはT?
  • three-type: 既存コードを壊さないようにTは残す。非nullがT!、nullableがT?

もちろん互換性の問題をクリアできるんなら two-type が理想的。nullチェックに対して、何らかのopt-in (コンパイラーの規定動作じゃなくて拡張にするとか、アセンブリ レベルの属性でTの意味を新旧切り替えるとか)を提供する必要がある。

Wire format

Wire format(JSONとか、要するに通信用に使う形式)問題。どうやったらJSON化とかの定義を楽にできるか、特に、シリアライズのレイヤーを緩い型付けのままどうやって強い型付けのロジックとつなぎこむか。

考えうるやり方は以下のようなもの。

  • 実行時に、辞書式のデータとインターフェイスとの相互変換する機能の類を提供
  • TypeScript みたいな「コンパイル時のみの型」(コンパイル結果からは型情報を消して辞書式アクセスに置き換え)
  • F# みたいな「型プロバイダー」の提供

C# Design Notes for May 20, 2015 #3911

https://github.com/dotnet/roslyn/issues/3911

ローカル関数、つまり、関数(メソッドとか演算子とか)の中で別の関数を定義したいという話。

まあたまにある、「メソッド X の中で、X からしか使わないメソッドを作りたい」という要件。これに対して、現状は無理で、代わりに XInternal みたいなメソッドを用意したり。あるいは、ラムダ式で代用するわけですが、ラムダ式はいくつかの制限が面倒なので改善したいと。

ラムダ式を拡張するか、ローカル関数用の構文を追加するかは検討中な物の、現状は後者、つまりローカル関数の追加で話が進んでいそう。というか、Design Notes 公開前に、pull-req とかブランチが見えてるんですが。

ちなみに、現状のラムダ式との違いは、

  • ジェネリックを使える
  • 再帰呼び出しもできる
  • イテレーターにもできる(yield return 書ける)
  • デリゲートの型を明示する面倒がいらない(ラムダ式は Func<int> みたいなやつの明示が必須)
  • というかデリゲートを介さない(オーバーヘッドが減る)

という感じ。

紹介されている用途の例:

  • イテレーターに引数チェックを追加
  • クイックソートとかの再帰アルゴリズムの実装
  • キャッシュ(2度目以降の呼び出しは辞書に格納した値を返す)
  • 特に、Taskのキャッシュ

C# Design Notes for May 25, 2015 #3912

https://github.com/dotnet/roslyn/issues/3912

いくつか、提案 issue に対してやるかどうかの判定。これに伴って、いくつかの issue が閉じられました。

その他、いくつか簡単な検討あり。

  • params IEnumerable: 性能的に、単に配列使うんじゃなく、もっといい実装を検討したほうがよさそう。
  • immutable な型に対する初期化子: 「wither」と一緒に検討したい。
  • vararg 呼び出し: params IEnumerable と一緒に検討したい。

C# Design Notes for Jul 1, 2015 #3913

https://github.com/dotnet/roslyn/issues/3913

Tuple がらみ、その後の状況(まだこれが最終決定じゃなく、いったんコミュニティからの感想受け付け用)。

名前関連

まず名前関連。あまり強く型付けしすぎないというのと、「C#のTupleはメソッド引数の延長」という発想の元、

  • 名前なし(匿名)Tuple作れるようにする
  • 同じ位置に同じ型が来ているTupleは、名前が違っても同じTuple型とみなす
    • ただし、(first: "John", doe: "Doe")みたいな、名前を明示する場合は順序の入れ替えあり
    • 名前違い同型のTupleで配列を作ると、型推論結果は匿名Tupleの配列

とかに。

エンコーディング

具体的な実装と、Tupleに対応していない他の言語・古いC#との繋ぎ。

たぶん、


public struct ValueTuple
{
    public T1 Item1;
    public T2 Item2;
    public T3 Item3;
}

みたいな型と属性で実現することになるはず。他の言語・古いC#からはItems1とかでメンバーアクセスすることになるけども、C# 7.0からはどう見えるべきか。混乱を避けるにはItems1でのアクセスは隠すべきだろう。

分解(deconstruction)

↓こういう分解用の構文を用意すべきかどうか。


(int sum, int count) = Tally(...);   

用意するならいくつか検討すべき疑問が残るものの、今のところその疑問を避けるべく、分解用の構文追加はしないでいる。

その他の課題

今のところ arity 0、1のTuple は考えていない。これらがあると便利だと思う(特に、コード生成の観点で)。でも、おそらく多くの疑問も起こすことになる。

その他いくつか、型変換(例えば、covariantな変換とか)も考えるに値するけども、今のところその検討は置いておく。