Archive for 3月 2015
ピックアップ Roslyn 3/29
C# Design Meeting Notes for Mar 10 and 17, 2015
https://github.com/dotnet/roslyn/issues/1648
議事録3/10, 17の2回分をまとめて1ページ投稿。この2回は、非null許容な参照型についての検討だったようです。
とれるであろう複数の選択肢について考察していますが、現時点での有力な選択肢は以下のとおり。
- string に対して nullable として string?、non-nullable として string! と書けるようにする
-
- 既存の string はそのどちらも明確化してない状態
- 内部的には属性を付ける実装になりそう
- 厳しくコンパイル エラーにするんじゃなくて、コード解析ベースのチェックになりそう
互換性を崩さないように作らないといけないので、妥協はせざるを得ない感じ。
.NET Core 対応
いくつか、.NET Core 対応用のpull-reqが出ていました。
https://github.com/dotnet/roslyn/pull/1571
https://github.com/dotnet/roslyn/pull/1623
以下のようなものへの依存を削ったそうです。
- バイナリ シリアライザー
- XmlResolver
- GetType(string, bool) とか Assembly.GetAssemblyName
- Encoding.Default
Warning Waves
https://github.com/dotnet/roslyn/issues/1580
警告の出し方もバージョン指定できる(“wave”を持たせる)ようにしない?という提案。
Roslyn になったことで、これまでよりもだいぶ詳細な警告出せるんだけど、警告を増やすってのは破壊的変更になる。「警告をエラー扱いする」オプションがあるんで、それを選択している人にとってはエラーと同じ。ということで、単純に警告を増やすのはリスクだそうです。
waveを持たせようという案は昔にも1度出ていたそうです。が、waveを持たせるよりも、警告1つ1つをon/offできる方がよいだろうし、そっちを実装する予定にしたので、waveを持つというアイディアはいったん止めた。でも、「警告1つ1つをon/off」はまだ実装できていないし、waveの方を再び考えてみる。という感じみたい。
Discussion – Patterns and Records
https://github.com/dotnet/roslyn/issues/1572
レコード型、パターン マッチングに関して、簡単な説明の後、公開質問がいくつか。質問は以下のようなもの。
- どのくらいパターン マッチングがほしい?
- 完備性のチェック(2/3のブログのcompletenessのところ参照)はした方がいい?
- 「型テスト」じゃなくて、タグを使うような実装もあり得るけども、どう?
- ↓どの型に対して、構文的なサポートがほしい?
- プリミティブ型やstring
- レコード型
- Nullable型
- プロパティを持ったオブジェクト
- 匿名型?
- 配列?
- List? Dictionary?
- タプル型?
- IEnumerable?
ピックアップRoslyn 3/22
最近さすがにだいぶ落ち着いて来た感あり。
今週は、今月4日のミーティング議事録が issue 上に上がったくらい。
Design Notes for Mar 4, 2015
https://github.com/dotnet/roslyn/issues/1303
アジェンダは以下の通り。
InternalImplementationOnly
attribute <no>- Should
var x = nameof(x)
work? <no> - Record types with serialization, data binding, etc. <keep thinking> (引き続き考える)
- “If I had a billion dollars…”: nullability <daunting but worth pursuing> (手ごわい。でも追及する価値ある)
InternalImplementationOnly属性
2/4 にブログで書いた奴のうちの1つ、InternalImplementationOnly 属性のその後。やっぱりあきらめるって。
今これを足すことで、今後の環境で目的を達成することはできる。でも、古い環境では何も制限をかけれなくて、結局、強制力が弱くてあまり意味がないだろう。という判断。
Should var x = nameof(x) work?
var を使った変数 x 宣言の中で、nameof(x) すると、型推論ができずにコンパイルエラーになるという挙動に関して。これは、仕様意図通りなんですが、この仕様でいいのかという議論が2月中にちょっと出ていました。その結論として、var x = nameof(x) はコンパイルできなくてOK、それが仕様ということに決定。
nameof は、同名のメソッドが定義されている場合や、、そちらが優先的に呼ばれます(後方互換性を保つため)。たぶん、そういう挙動との兼ね合いのせいだと思うんですが、nameof と書かれていても、結果の型が string に確定しません。その結果、var x = nameof(x) を認めるのは、型推論にかかるコスト的に厳しいはず。それで、この書き方を認めない仕様になっています。
Records
レコード型についてのディスカッションをしたそうです。レコード型自体については2/5のブログを参照。今回は、要件整理のみ。
C#でよく言われる課題として、シリアル化とUIデータ バインディングが面倒という話が前々からあります。といっても、これらに特殊対応するような言語機能(JSONリテラルとか、INotifyPropertyChangedの自動実装とか)の追加は得策ではない(きっと陳腐化する)。とはいえ、もっと汎用的な機能として何かできないか考えないと行けない。
シリアル化とかデータ バインディングとかを考えると、「同じ形状の(同じ型、同じ名前のメンバーを並べた)別実装」みたいなものが必要になったりします。
- シリアル化ライブラリは、オブジェクトが mutable であることを期待するものが多い
- データ バインディングでは、値の変更通知が必要
- シリアル化・データ バインディングでは、メタ データを使った処理をしたい
- 一方、実行効率を考えると、ビジネス ロジックでは強い型付けで処理をしたい
このためにとれるアプローチとしては、
- 1つの型に手作業で全要件満たすようなコードを書く
- シリアル化用、ロジック用、データ バインディング用など、複数のオブジェクトを作る
- dictionaryなどを使った、リフレクション不要なやり方でオブジェクトを作る
- F# のType Provider みたいに、型情報を偽装する
- コンパイル時コード生成など、メタプログラミングで複数の型やその相互変換コードを生成する
引き続きこういうシチュエーションに関する考察は続けていく。また、次のステップとして、シリアル化やプレゼンテーション層技術を担当している他のチームともコンタクトをとっていく。
Nullability and reference types
割かしもう繰り返しになっていますが、今から.NETに非null許容参照型を入れたいとなった場合の課題の検討。
- 後方互換性を保たないといけないので、現状の書き方(例えば、stringだけ)で nullable/non-nullable にすることはできない。string? と string! みたいな新しい書き方が必要。
- 非null許容を T! で表すものとして、default(T!) はどうあるべきか。.NET の型は、配列初期化時など、必ず規定値 default(T!) として初期化としてされる。
- T! なフィールドに対して、new した時点で確実に初期化されている保証をどうやって実現するか
- T?, T! を言語的に導入できたとして、既存のライブラリがこれに対応しだすと、破壊的変更になる
- null チェックなしで T を T! には代入できない
- メソッド引数の T を T! に変更すると、呼び出し部分がエラーになる
- 戻り値の T を T! に変更すると、var (型推論)でメソッド戻り値を受けている場合、その先でエラーになる可能性がある
課題は難しくて、非null参照型を強く保証することは無理そう。でも、意味のある範囲で今よりもnull参照例外を減らせるようなアプローチができないとは言わない。引き続き検討を続けたい。
Orange Cube
「UnityのためのC#勉強会」に行ってきました。
弊社同僚 細田とでやったデモで使ったソースコードは GitHub 上に置いてあります。
https://github.com/ufcpp/UnityCsharp20150321
セッション資料の pptx もこの GitHub リポジトリ内に含まれています。
会社内の成果ベースでの発表は久しぶりでした。発表しようしようと思いつつもタイミングを逃し続け、気が付けば結構いろいろ仕上がってしまってて。ちょっと1回のセッションに一気につめこみすぎたかなぁとか思いつつの発表でした。
ピックアップRoslyn 3/14
今週のProposals
昔、「UnreachableAfter属性」で提案されていたもの。エラーチェックなどの際、必ず例外を投げるようなメソッドを作ることがあります。この場合、そのメソッドよりも後ろは絶対に実行されないわけですが、それをコンパイラーがわかるようにしたい(unreachableコード判定用)という要望があって、その解決策としての提案。
それが今回、属性じゃなくて、System.Neverっていう特別な型を作ってはどうかという提案が出ました。Scalaは、Nothing型で同様のことをしていて、そこからの着想だそうです。
Design Notes for Feb 11
2/11 の C# デザイン ミーティング議事録が今頃公開。
2/4 以降、議事録が issue ページ化されてなかったわけですが。
あんまりディスカッションしたいポイントがないからページ立てるモチベーションが低かったんですかね。議事録自体はあるみたいで、2/4のissueページの方で、「2/4以降のやつはないの?」とつつかれて「少しずつ出していく」との返事が返ってきてました。とりあえず、その翌週分、2/11のものがissueページ化。
内容的には、
- Destructible types:
- #161 の提案ベースだとダメそう
- 「決定論的なオブジェクト破棄」というゴール自体はなくしたくない
- IDisposable とか、既存コードとの親和性が高いよりよい方法が望まれる
- Tuples
- かなり乗り気なんだけど、もっと詰めないといけない点が何点か
という感じ。
タプルに関して、自分が興味ひかれたところだけ抜き出すと:
まず、タプル間の変換をどうしようという話。タプルの変換というと、以下のようなパターンがあり得るけども、どれがいいか(どれもダメっていう結論もあり得る)。少なくとも、reordering と renaming は絶対に両立できない。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(string name, int age) t = ("Johnny", 29); | |
/* Covariance */ | |
(object name, int age) t1 = t; | |
/* Truncation */ | |
(object name) t2 = t; | |
/* Reordering */ | |
(int age, string name) t3 = t; | |
/* Renaming */ | |
(string n, int a) t4 = t; |
もう1つは、タプルの分解時に、変数名の補完が効くためには、受け手が右辺にないとダメよねという話。代入だと、受けてが左側に来るので、変数名を打ってる時点では右辺の型がわからず、補完が効かないのがめんどくさい(LINQ で、SQL もどきのくせに1行目が from なのも同じ理由。from から初めて、最後が select なら変数の補完が効く)。右辺側に代入するような新しい構文が要るかも(以下はその一例)。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Tally(myValues) ~> (var sum, var count); // strawman right side alternative | |
Console.WriteLine($"Sum: {sum}, count: {count}"); |
最後、out 引数を暗黙的にタプル化したいという話。F# だとできるので。例えば以下のような感じ。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
bool TryGet(out int value){ … } | |
/* current style */ | |
int value; | |
bool b = TryGet(out value); | |
/* New style */ | |
(int value, bool b) = TryGet(); |
「C#スクリプト」パッケージ
工数的な問題で長らくいったん消えていたC#スクリプト関連のAPIが、NuGetパッケージに帰ってきそうです。
Roslyn プロジェクトはNuGetパッケージの毎夜ビルドにmygetを使ってるみたいなんですが、そのmyget(以下のURL)ビルドでは、スクリプトAPIが利用できるようになったとのこと。
RC2 扱い。RC2 のリリースいつだろう。
ピックアップ Roslyn 3/7
構造体の引数なしコンストラクター
今週は大変残念なお知らせが…
1つ目。構造体の引数なしコンストラクターの導入、やっぱり見送り(今のCTPだと実装されているけども、次のCTPで元に戻す)になるみたい。
構造体Tに対して、new T() が default(T) と同じ(0 初期化)になるという前提の最適化がすでにあちこちにあって、.NETのフレームワーク/ランタイムのレベルでもこの前提になっちゃってるところがあるみたい。で、new T() でコンストラクターが呼ばれないバグが、ランタイム レベルであって、今、C#に構造体の引数なしコンストラクターを導入するのは無理くさい。
個人的には、C# 6.0 に入って(入ることになってて)ありがたかった機能の結構上位にあったので残念。というか、一応名前が「RC (リリース候補)」になった矢先にですか…
今週のProposals
なんか今週は、「実現性薄そうだけどとりあえず議論しようか」感が漂っていたり。新しい提案 issue ページが結構な数「C# 7 and VB 15」マイルストーンに登録されていました。
enum のメンバーを、E.A | E.B みたいに書くんじゃなくて、型名を省略して A | B 的に書かせてくれという話。
実は、C# 6.0 の時点ですでに、using static を使って近いことはできるようになっています。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using static X; | |
[Flags] | |
enum X | |
{ | |
A = 1, | |
B = 2, | |
C = 4, | |
} | |
class Program | |
{ | |
static void Main(string[] args) | |
{ | |
Console.WriteLine(A | B); // X.A | X. B | |
} | |
} |
その上で、もう1歩踏み込みたい?という話。型の推論は効いてほしいかどうか。例えば、以下のコードをコンパイルできるようにしたいか。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using static Color; | |
using static Mood; | |
enum Color { Red, Blue } | |
enum Mood { Cheerful, Blue } | |
class Program | |
{ | |
static void C(Color c) => Console.WriteLine($"color: {c}"); | |
static void M(Mood m) => Console.WriteLine($"mood: {m}"); | |
static void Main(string[] args) | |
{ | |
C(Red); | |
M(Cheerful); | |
C(Blue); // Error CS0229 Ambiguity between 'Color.Blue' and 'Mood.Blue' | |
M(Blue); // Error CS0229 | |
} | |
} |
2つ目。C# の仕様的に、ジェネリックな属性クラスを作らせてほしいという話。
流れ的には、「メリット薄くない?」「実装手間考えるとあんまりやりたくない」的空気。
3つ目。静的メソッドも「拡張」できるようにしてほしいという話。
やりたいけど具体的な文法案はまだ固まっていない状態なので、このページのコメントでいろんな文法案が出てきています。
とはいえ、「インスタンスメソッド以外、プロパティとかも含めた拡張」という、もっと広いプランが C# 7.0 の当初から出ているので、おそらくはそっちに統合されるのではないかと。
this 相手に拡張メソッドを呼びたいとき、this.Method() って書くの面倒だし、インスタンス メソッドとの一貫性に書けるから this の省略を認めてほしいという話。こいつはページのコメント、いまいち盛り上がりに欠けてたり。
「クラス自身に対して拡張メソッド呼ぶの要る?自身に対してだったら普通のインスタンス メソッドを足せよ」という話があって、これができないわけですが。interface を明示的実装して、その interface の拡張メソッドを呼びたいということはまれにあるんですよね。ただ、稀にしかないことのためにコンパイラーの複雑化(拡張メソッドを探すのもそれなりのコスト)を招きたいかといわれると。
クラスとのフィールドとかに var を使わせてという話。
これが今まで認められていない理由は2つあります:
- (ポリシーとして) メンバーの型はドキュメントとして扱われるもので、省略すべきではない
- (実装上の問題として) 循環依存で死ぬ
循環依存は例えば以下のような感じ。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class A | |
{ | |
public var N = B.M + 1; | |
} | |
class B | |
{ | |
public var M = A.N – 1; | |
} |
この問題を超えるメリットはないかなぁ…
あと、脱線で、const var を認めてほしい的な話も。const var って、constant (不変)で variable(可変)?variable が数学用語としての variable から来ているにしても、字面やばい。
ほぼ同機能を実装することになっているものの、C# に対してディスカッションが非常に少ない VB ですが。その VB で、AddressOf を省略させてという話。
Unicode Version Change in C# 6.0
こないだ、ufcpp.net 本体に「[雑記] C# ソースコードと Unicode」とか書いてたわけですけども。1か所、C# 6.0で破壊的変更になっちゃうもの(中黒「・」が識別子に使えなくなった)の話も書きました。
まあ、「Unicode の変更だ」といわれるとしょうがなく。Java 7 でも同様の問題出てて、しょうがないよね的な空気になっていたり。
なんですが、それはそれで、ドキュメント化は要るんじゃないかな、というか、今、Roslyn プロジェクト内で破壊的変更のドキュメント化作業もやってたよね。と、ふと思い立って、報告してみることに。そしたらその日のうちにドキュメントできてた。
最初にこの話題で盛り上がってたのはグラニの人ら(Build Insider の記事の下の方にその話題あり)なんですけども。今度会うとき言ってみとこう。