Archive for 2月 8th, 2015
C# 7に向けて(7): まだ具体案の見えていないもの
「C# Design Notes / テーマ」で「どういうことがしたいか」だけ列挙されているものの、具体的にどういう仕様を追加するかまではまったく決まっていないものがまだまだ結構あります。そんな具体案の見えていないものに対して、いくつか、issue ページができて、オープンなディスカッションを始めたようです。
あと、Issue に対してマイルストーンも切り始めたみたいで、「milestone: “C# 7 and VB 15″」で検索すると一覧が出てきます。
- [Proposal] Support System.Delegate as a generic constraint #158
- Proposal: bestest betterness #250
- Proposal: Declaration Expressions #254
- Proposal: support await in Catch and Finally in VB #256
- Proposal: Virtual extension methods #258
- Proposal: Nested local functions and type declarations #259
- Proposal: language support for async sequences #261
- Proposal: support an enum constraint on generic type parameters #262
- Declaration of ref/out parameters in lambdas without typename #303
ちなみに、#158 とか #303 とかは、C# チーム以外のコミュニティ提案のものです。
await in Catch and Finally in VB
C# 6で、await 演算子を catch/finally 句内に書けるようになって、多くの C# 開発者が歓喜した(C# 6の正式版リリースが待ち遠しい)と思います。
そして、「同時期の C# と VB の機能はだいたい一緒」なので、VB 14 でも… と思いきや、VB 側だけ間に合わなかったみたいでして。15 送りに…
bestest betterness
オーバーロード解決の話。
C# は同じ名前で引数違いのメソッド(メソッドのオーバーロード)を持てるわけですが、X(object) と X(string) に対して string の実引数を渡すときみたいに、どちらでも呼べるような場合があります。こういう場合、どちらのメソッドが呼ばれるかは、betterness rule (優れた方を呼ぶルール)というのがあって、型の一致度がよりよい方が呼ばれます。X(object) と X(string) の例でいうと、string の方が優先されます。
まあ、いくつか、直感的に betterness から外れる(一見すると一致度が高く見える方が呼ばれない)ような場合もあるんですが、だいたいは継承が絡んでいたり、ポインターが絡んでいたりという、複雑な場合です。例えば、後から基底クラスにメソッドが増えた時に、派生クラスの利用者側コードを壊さないように、型の一致度よりも「派生クラス側にある」ということが優先される場合があります。
こういう、合理的な理由のある「betterness から外れるもの」はいいとして、いくつか、C# の新機能のせいで「よりよい方」が変わってしまったものや、バグで「よりよい方」が選ばれていなかったのを修正したものがあったりします。C#チームは、こういう変更を「better betterness」(betterness rule をよりよく準拠するようにしたよ)とか言っていたみたいです。
「C#の新機能紹介」的な記事ではめったに紹介されませんが、実、細かくこういう better betterness 変更が毎度あったりします。で、C# 7/VB 15 でもまた better better betterness (より、より、よく)するだろうと。ついに、bestest betterness (最上級の best をもう一段最上級にした、日本語でいう「御御御付け」みたいなふざけた単語)とか言いだす始末。
generic constraints
- [Proposal] Support System.Delegate as a generic constraint #158
- Proposal: support an enum constraint on generic type parameters #262
ジェネリック制約(ジェネリック型引数に対して、where 句で「このTはこのインターフェイスを実装していないとダメ」とか「このTは構造体でないとダメ」とかの制約をつけるもの)に、「Tはデリゲート」(つまり、T() で呼び出ししたい)とか、「Tは列挙型」(つまり、int との相互変換ができたり、| でビット フラグを作れたり)とかの制約を付けたいという話。
むっちゃ欲しい。
とはいえ、これって、現状の .NETランタイム/.NET の IL レベルでは対応していないので、ランタイム側に手を入れるか、何かよっぽど仰々しいコード生成でもするかしないと無理なはずで、結構難易度高そう。要望としては強いだけに、何とかクリアしてほしいものの。
Virtual extension methods
C# 3 で入った拡張メソッドはなかなかに便利なものですが、まあ、実態はただの静的メソッドなので、virtual な動作(変数の型ではなくて、その中身、インスタンスの実行時の型を見て処理を分岐)をすることはできません。
これに対して、virtual な動作ができる、拡張メソッド的な何かもあってもいいんじゃないかという提案。
今のところ、Java の default method (インターフェイスのメソッドに、既定の実装を与える構文)みたいなものと説明されていますが…
Java の default method だと、
- 利点: virtual な動作ができる。クラス側で実装を変えれる。
- 欠点: インターフェイスの作者しか実装を与えられない。LINQ みたいに、第三者が拡張できない。
なわけですけども…
Java の default method は、「拡張」が目的じゃなくて、「後からインターフェイスにメンバーを足しても、既存コードを壊さない」(古い Java や現状の C# では、一度 public にしてしまったインターフェイスにメンバーを足すのはご法度)というのが一番の目的だと思うんですよねぇ。同じようなものに「Virtual extension methods」という呼び名はあんまり与えてほしくないというか…
あと、default method 的なものを導入しようと思うと、.NET ランタイムに手を入れないと行けないはず。C# コンパイラーだけでは対応できない。
Nested local functions and type declarations
関数の中(メソッド、演算子、プロパティなどのbody内)で、メソッドやクラスを定義したいという話。
まあ、そうしたいことは昔からたびたびあるんですが。これ、C++ でもたびたび話題になるやつですよねぇ。C++ だと、確か、「変数宣言との区別があいまいになる」ってのが、この機能が入らない理由だったんじゃないかと。↓みたいな書き方が許されるので、「関数内関数は」これとの相性がよろしくない。
C# だと大丈夫なのかなぁ。C++ と同じ、「型名 変数名」で変数宣言する言語ですけども。変数宣言時のコンストラクター呼び出しを X x = new X(); と書く分、行ける気はしますが。
async sequence
C# 5で入った非同期メソッド(async/await)は結構革命的な機能だったわけですが、この機能は「単一の値を返す」のにしか向いていなくて、シーケンスを返すにはいまいちです(LINQ みたいな遅延リスト的な挙動ができない。配列なり List なりを作って返すしかない)。
現状、非同期にシーケンスを返すには、Rx を使うのが一番ではあるんですが、これに対して await 演算子みたいな C# 言語レベルでのサポートはありません。そういう言語レベルのサポートも欲しいよねという話。
await と Rx があるんだから割かしすんなりできそうに見えて、決め手に欠けてなかなかよい仕様が出てこない感じ。「非同期」自体が難しいテーマですからねぇ。C# 5の非同期メソッドも「汎用性を考えるとこうすべきなんだけど、使い勝手とパフォーマンス面を考えるとこうせざるを得ず」みたいな決断の跡がいくつかあって。 非同期シーケンスという要望もその当時からずっとあって、今まで決め手が得られていない難しさがあります。
ラムダ式での ref/out 引数
ref/out の付かない通常の引数の場合型推論が効くのに、ref/out 付きの場合には型の明示が必須なの、何とかしろ。という話。
これは割かし低リスクっぽい。まあ、ref とか out 自体をそれほど使わないという辺りがネック(リスクも低いけども、メリットも少ない)。