++C++; // 未確認飛行 C ブログ

http://ufcpp.net/

Archive for 2月 2015

Roslyn 2/28

leave a comment »

割と「週刊」化している、 https://github.com/dotnet/roslyn 内の今週の動き。

Milestone: C# 7

Milestone が「C# 7 and VB 15」なものに2項目追加。

プロパティ内限定(get と set の両方で使いたいけども、その他のメンバーからは触られたくない)スコープが欲しいという話。

C# 2.0 とか 3.0 の頃から欲しいとは言われていたものの、全然入らなかった機能。当時は自動プロパティ(3.0 で入った T X { get; set; } だけでプロパティが作れるやつ)だけでも、Anders (.NET のものすごく偉い人)がなかなか Go サインを出さなかったらしいですし、時代もだいぶ変わった感が。ここ数年、Anders はご意見番的な立ち位置で、Mads (C# チームのPM)の統括に代替わりできているみたいで。

仮想メソッドを派生クラスでオーバーライドする際に、戻り値に共変性を認めたいという話。例えば、class Derived : Base {} があるとき、ある規定クラスが virtual Base X() メソッドを持っていたとき、こいつの派生クラスは override Derived X() を定義したい。Java には昔からあって C# でもたまに欲しくなる話ではあります。

実装的には、.NET ランタイム(IL 仕様)の変更は不要そう。派生側に、override Base X() (基底クラスのやつのオーバーライド)と、new virtual Derived X() (別の仮装メソッドを追加)の両方を作って、override 側から new 側を呼び出すようなコードを生成すればいいはず(そういうやり方は、現在の C# では書けないものの、IL 仕様的にはできる)。

決定論的なモジュール ID

現状の Roslyn C#/VB コンパイラーは、コンパイルのたびに生成結果のモジュール(exe や dll)のバイナリが変わってしまうそうです。これは、ポータビリティの観点からあまりよろしくないので、決定論的な生成結果を得るための調査を始めた模様。

一番の原因は、モジュールの ID にタイムスタンプが入っているかららしいです。これを、モジュールのハッシュ値みたいなものに変えたいというのがまず第一。ただし、これが決定論的であるためには、タイムスタンプに実際のコンパイル時刻などは使えなくなります。ちゃんとした時刻が入っていることを期待したプログラムの動作保証がなくなります。

そして、ハッシュ値が決定論的であるために、コンパイラーが生成するモジュール自体が決定論的である必要があって、そのためにいくつか別の課題が上がっています。

広告

Written by ufcpp

2015年2月28日 at 19:47

カテゴリー: 未分類

VS 2015 CTP 6、Microsoft.CodeAnalysis.Analyzers RC 1

leave a comment »

昨日、Visual Studio 2015 の CTP 6 が出たみたいですが。

まだRC(リリース候補)じゃなくてCTP(テクニカル プレビュー)なんですねぇ。

一方で、Microsoft.CodeAnalysis.Analyzers (Roslyn の NuGet パッケージ配布)は RC1 になりました。Visual Studio 2015 CTP 6 の Roslyn (要するに、CTP 6 が使っている C# コンパイラー)はこの RC 1 のやつだそうです。

つまり、C# 6.0 は RC 1 になりました。

CTP 6 での C# 6.0 の更新点

バグフィックスとかは置いておいて、C# 6.0 の文法的な話でいうと、2点更新があります。

  • Exception Filters の仕様変更
  • IFormattable な String Interpolation

Exception Filters の仕様変更

例外フィルターで、if ではなく、when を使うようになりました(新しい文脈キーワード。catch の条件句の直後でだけキーワードになる)。

if だとね… 波かっこ {} の有無で意味が変わっちゃうとかいう恐ろしい仕様だったので。これは仕方がない。

IFormattable な String Interpolation

「C# 6.0 正式版までには入る」機能のうちの最後の1つ、FormatProvider 指定できるバージョンの文字列補間が実装されました。

これが、C# 6.0 の新機能の中で唯一、.NET Framework のバージョンアップする(もしくは、同シグネチャのクラスを自前で追加実装してやる)必要のある機能。上記コード例は、ターゲットを .NET Framework 4.6 にするか、FormattableStringFactory/FormattableString クラスを自作しないと動きません。

ちなみに、FormattableString は、当初、構造体にするかもという話も出ていましたが、結局クラスになったようです。あと、$”” の展開結果は、直接 new FormattableString(format, args) するんじゃなくて、ファクトリ メソッド FormattableStringFactory.Create(format, args) を介して作られるようになったみたいです。後からの拡張ができるようにしてあるのかも。

Written by ufcpp

2015年2月26日 at 00:09

カテゴリー: 未分類

Roslyn 2/21

leave a comment »

https://github.com/dotnet/roslyn 内の動きから、今週もいくつかネタを。

バージョン違いでコンパイル

そういや先日のネタの為に、複数バージョンのC#コンパイラーを同時に読んで、結果を色分けして表示するPowerShellスクリプトを書いたわけですが、その後も度々活躍していたり。Roslynのリポジトリ見てると結構、古いバージョンだとどうだったんだっけ?とか気になったり。

ということで、このスクリプトもGistにでも置いておきます。

StaticClassInstance

gitter運用始まりました

Miguel(Monoの偉い人)がgitter立ててた。

https://gitter.im/dotnet/roslyn

gitterについて紹介しておくと、GitHubと連携して、リポジトリや組織単位の部屋を立てれるチャットサービス。発言はGitHub互換のmarkdownで書けるし、#123とか書くとGitHubの該当issueへのリンクになるし、:+1:とかでの絵文字も使えるみたい。

 Portable PDB

Portable PDB (program database)の仕様が公開されたみたい。

https://github.com/dotnet/roslyn/blob/portable-pdb/docs/specs/PortablePdb-Metadata.md

PDBは、デバッグとかビルド用にプロジェクト内のソースコードの状態が色々記録されてるファイル。例えば、スタックトレースとかブレイクポイント用に実行ファイルのどこがどのソースコードの何行目かとかの情報が入っていたり。あと、インクリメンタルビルドのためとかにも使っているみたいです。

これまでは、一応PDB読み込み用のライブラリは公開されてたりはするものの、詳しいドキュメントはいっさいなかったみたいです。

この手のデータは、このMSが使ってるPDB以外でも、大抵のコンパイラーがそれぞれ独自の形式を持ってたりします。ほんとバラバラ。C#でも、MS製コンパイラーはPDBを使っていますが、MonoのmcsコンパイラーはMDBっていう別形式を持っています。

今回、オープンになった形式(Portable PDB)は、.NETのメタデータの上位互換なフォーマットみたい(物理フォーマットは同じで、メタデータと同じ実行ファイルに混ぜることも可能。要は論理スキーマの追加)。

まあ、デバッグに必要な情報はかなりの部分メタデータと被るので。世の中には「C++でもリフレクションできるよ?PDB読めば」とかいう猛者もいらっしゃるくらいで。ちなみに、「PDBってVC++専用でしょ?」って聞くと、「もちろんコンパイラーごとに別実装する」との返事が返って来たり。

などという深い闇を産んできたわけですが、オープン化で状況改善しそうでほんとになにより。

default(StaticType)

静的クラスがらみのバグフィックスと、それの結果、一部旧コンパイラーから破壊的変更になったという話が1件ドキュメント化。

https://github.com/dotnet/roslyn/blob/master/docs/compilers/CSharp/Static%20Type%20Constraints.md

C#の仕様的に、静的クラス(static修飾を付けたクラス)は絶対にインスタンス化できないわけで、静的クラスの変数はそもそも作れなくしてあります(コンパイルエラー)。

静的クラスAがあったとき、

A x;

はエラーになります。これくらい素直な場合はいいんですが、めんどくさいケースがいくつかあります。まずは、varでの変数型推論。

var x = default(A)

そもそも、default(A)を認めるなよって話ではあるんですが、旧コンパイラーでは default(A) を書けちゃうそうです。Roslyn新コンパイラーでも、互換性のため、default(A)自体は書けるようにした(バグだけど直さない)とのこと。

そして、そのせいで、先ほどのvar x = default(A); が問題に。別途、「型推論の結果、varが静的クラスになるのは認めない」というルールを設定。

次にはまったのは、これをジェネリックなメソッドに渡す場合。void M<T>(T x)がある時の、

M(default(A));

これも別途、推論結果で型パラメーターが静的クラスになったときをエラーにしないといけない(最初、コンパイルエラーになってなくて、バグ報告されてた)。

そして、これとは別に、旧コンパイラーにはもう一個バグがあって、

((dynamic)3).M<StaticType>()

これがコンパイル通るそうです。dynamicが絡むとチェックが甘く。Roslynではこれは直したそうで、破壊的変更になってしまっているとか。まあ、実行時エラーになって他ものがコンパイルエラーになるだけですけども。

Roslyn内のコードをいくつかC#6化

試しにアナライザーのいくつかをC# 6を使って書き換えてみたそうです。

https://github.com/dotnet/roslyn/pull/740

目的は「少しやってみて、皆の印象を聞きたい」みたいな感じみたい。なのでごく一部だけ(Roslynのアナライザーを使えば機械的に全置換とかもできるけど、それはやってない)みたい。

Written by ufcpp

2015年2月21日 at 23:52

カテゴリー: 未分類

Roslyn コンパイラー仕様

with one comment

まだ pull-req 通ってないんですが、Roslyn リポジトリ上にこんなものが。

https://github.com/dotnet/roslyn/pull/536

コンパイラー仕様のドキュメント化、始めました。

“コンパイラー仕様”

コンパイラーを作っていると、標準化されている言語仕様では不十分な仕様ってものがどうしても出てきます。C# コンパイラーにもいくつかそういうものがあるんですが、「オープン化したんだからそういう隠れ仕様もドキュメント化しないとダメだよね」という感じで、その手始めに、コンパイラーチームの内部 OneNote で書かれていた仕様を .md 化してリポジトリに追加しようとしているみたい。pull-req が通った暁には、/docs/compilers フォルダー以下にこういう “コンパイラー仕様” が並びます。

具体的にどういうものをドキュメント化しようとしているかというと、

  • コマンドライン スイッチとその意味
  • 以前のバージョンのコンパイラーからの破壊的変更
  • 標準仕様に反するコンパイラーの内部挙動
  • 言語仕様に記述されていないコンパイラー機能
    • COM 関連や、マイクロソフト特化の動作
    • コンパイラーの挙動に影響を与える “well-known” な属性(Obsolete とか Conditional のこと)
    • “ruleset” (FxCop 的なものの、どの警告を出してどの警告は抑止するみたいなルール)のファイル構文(syntax)と意味論(semantics)
  • C#とVB間の相互運用のための機能
    • 名前付きインデクサー(インデックス付きプロパティ)のC#からの利用
  • 言語仕様で明確でなく、発散の余地のあるコンパイラー挙動
  • 制限次項(例えば識別子長など)
  • バージョンごとの変更履歴

など。

そんなのよく気づいたな

今回公開されたコンパイラー仕様のうちの1つ、「Definite Assignment」がネタとして面白かったんで紹介。要するに、「変数には確実に値を与えておけ」仕様に関する話。

C#では、未初期化のローカル変数の参照を認めていません。これ自体は言語仕様にも書かれていることです。問題は、「何をもって未初期化・初期化済みを判定するか」という部分。判定ロジックに関する詳細が言語仕様に足りていないので、「明確でなく、発散の余地のある挙動」になっているみたいです。

例えば、このページで紹介されている例は以下のようなもの。

C#コンパイラーは、到達不能な場所では「未初期化変数を使った」判定をしないみたいです。つまり、 if (false) { ここ } とか、if (true) {} else { ここ } とかでは、別に未初期化変数を使ってもコンパイルエラーにならない。

で、コンパイラー挙動がぶれているのは、さらに、ショートサーキット演算(&& とか || とか、左辺の時点で結果が確定したら右辺を実装しないもの)と組み合わさった場合。false && (ここ) とか true || (ここ) とかは絶対に通らないわけで、前述の if の例に習うなら、別に「未初期化変数を使った」判定をさぼってもいいはず。

ところが…

DefiniteAssignmentUnreachableCode

C# 3.0~5.0 まではエラーになるんですって、これ。C# 2.0の頃はエラーになってなかった。そして、Roslynでもエラーにならなくした。というか、明確なルールを加えた。とのこと。

言われるまで気づかなかった… まあ、こんなコード書かないし、誰も気づかないから言語仕様に漏れるんですが。

なんなんですかね、これ。パターン マッチングとか宣言式とかを実装する過程でこれに類するコードが生成されちゃって困ったとかがあったんですかねぇ。それとも、誰かC# 2.0の頃にこの類のコードを書いてる人がいて、C# 3.0の時に「破壊的変更」を不具合報告入れたとか?

Written by ufcpp

2015年2月17日 at 23:39

カテゴリー: C#

Tagged with

Roslyn issues 2015/2/16

leave a comment »

前回でひと段落したC# 7提案関連の話、一応リンクまとめておきますか。

そして今後は週1程度で個人的に興味持ったものをピックアップしていこうかなぁという感じなわけですが。

とりあえず、第1回。

Non-nullable references: a few difficulties and possible solutions

https://github.com/dotnet/roslyn/issues/227#issuecomment-73928184

非null許容な参照型に関する issue ページに、Mads (C# チームの偉い人)が結構まとまった内容のコメントを付けてた。

要点は

  • フィールドだと他の場所で書き替えられる可能性があるから、非null保証しにくい
    • 参照型 T を、非null参照型 T! の変数で受けてから使う、みたいな処理が必要
    • パターンマッチングを使えば、x is T! y みたいな書き方はできる
  • 規定値どうしよう
    • 参照型の規定値は null なんで、既定でない値の代入が必須
    • 特に配列とかout 引数の場合に心配
  • ライブラリの互換性
    • 非null参照型が入ったら、既存のライブラリをぜひともこれに対応させたいって思う人がかなり多いはずだけども、既存の参照型 T を非null参照型 T! に書き替えると破壊的変更になる
    • コードを壊さないようにするためには T から T! への暗黙的変換が必要。でも、暗黙的にしてしまうと、せっかくの非null型の魅力半減

という感じ。

Avoid unnecessary boxing with String.Concat

https://github.com/dotnet/roslyn/pull/415

C# で、”int ” + 1 みたいな書き方(文字列 + その他の何か)をすると、string.Concat 呼び出しにコンパイルされます。この例で言うと、string.Concat(“int”, 1)。

で、string.Concat の引数は params object[] です。整数とか、値型に対して使うとボックス化が発生。

で、この無駄なボックス化を避けるために、値型だった場合、先に ToString メソッドを呼んでしまおうという提案がされています。もちろん挙動変更なので慎重に検討。

とりあえず、この挙動変更で問題が出るようなプログラムはなさそうには思います。また、C# の仕様書を読み合わせてみても、問題のある(仕様違反になる)変更ではないはず。

What language proposals would benefit from CLR changes?

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

C# 6までは、とりあえずコンパイラーの修正だけで実現できる機能ばっかりでした。

C# 7の提案に入ってからは、まずは要望だけ洗いだしている状態で、コンパイラーだけでやるべきか、.NETランタイムに手を入れるべきかも含めて検討中。

で、今週、「.NETランタイムにも手を入れるならこういうこともできるよ。他に何か要望ある?」ページが建ちました。

Improve memory managment in async methods

非同期メソッドやイテレーター中でローカル変数を定義すると、コンパイル結果的にはクラス生成されて、ローカル変数だったものが実はフィールドに格上げされます。これは、awaitやyield returnを超えて同じ変数を使うためには必要な処置です。

問題は、awaitを超えて変数を使わない場合。awaitを超えないということは、別にフィールドにしなくても挙動は変わりません。ところが、現状のC#コンパイラーは、awaitを超えない場合でも変数をフィールドの格上げします。理由は、デバッグ時、非同期メソッド内に break point を仕掛けて止めた場合、awaitより前の変数の状態を見たいときがあるから。つまり、デバッグのためだけに、無駄な処理を行っています(ローカル変数のフィールド化は、メモリ管理上、結構な無駄)。

この挙動変える?break point で止めた時に await より前の変数覗きたい?デバッグ ビルドの時だけフィールドに格上げすべき?みたいな内容の issue ページ。

Written by ufcpp

2015年2月16日 at 02:20

カテゴリー: C#

Tagged with

C# 7に向けて(9): Method Contracts

with one comment

今 issue ページができてて大きめのものはこれが最後のはず。Method Contracts。メソッドに対する「契約」。

結構長かった… 結局、全9回に。今後は、「週刊ブログ」程度でよくなるはず。きっと。

契約プログラミング

そもそも「contracts」とは何か的な話は、昔書いたスライド貼って済まそう。

(補足: このスライドでは非null制約を例に挙げて説明していますが、非null制約は契約でやるよりも、「非null参照型」を作る方がいいと思います。C# 7向けの提案の中にはこの「非null参照型」も含まれています。)

一応、.NET 4の頃から、ライブラリとツールでのサポートはありました。

また、研究的な位置づけのプロジェクトでは、C# に契約プログラミング機能を足したプログラミング言語(Spec#)もありました。

まあでも、C# が言語機能レベルでサポートしないと流行らないよね、きっと。という状態。

問題

.NET 4で契約がらみのクラス(Contract)が追加されてからも、実際のところ、このContractクラスを使ってくれたライブラリは少ないです。

どういう問題があるかというと例えば、

  • Contract. を付けないと行けなくていちいちめんどくさい
  • 契約の宣言場所がメソッド本体の中(本来、外に見せない内部実装にあたる場所)にある
    • 契約は外から見えるべき
  • ポスト プロセスが必要
    • Contract.Requires/Ensures を書いている場所では実際には何も起こらず、コンパイル結果のILをさらに書き替えてチェックを行う仕組みになってる
    • ドキュメントへの反映(「このメソッドはこういう契約を持っている」みたいなのを doc コメントに反映)もポスト プロセス
  • ソースコードの静的解析が結構重い
  • Visual Studio の上位エディション(確か、当初、Ultimate 限定?Premium でも行けたかも)が必要
    • ポスト プロセス、静的解析ともに

提案: C# 言語機能での契約

文法的には Spec# の頃とあんまり変わらないものになりそう。

requires (事前条件: 引数が満たすべき条件) や ensures (事後条件: 戻り値が見たすべき条件)の違反は fail-fast (エラー ログを残して即座にプログラム終了)にするようです。契約は、理想を言えばコンパイラーによって違反は全部コンパイル エラーにしてしまう方がいいものです(単に、技術的困難から実行時に残るだけ)。テストによって契約違反は取りきるべき(ちゃんと、呼び出し元がすべて責任をもって引数チェックしてからメソッドを呼ぶ)もの。なので、規定動作は例外すら出さず、強制終了。

一応、requires/ensures の後ろに else throw を付けて、この挙動を変える(例外を投げるだけにする)機能は検討されているようです。

あと、呼び出し元側で責任をもってチェックする必要があるということは、requires/ensures 句内では、メソッドよりもアクセス制限の強いメンバーの参照は禁止されるべきです。internal なメソッドの契約で private フィールドを参照したりはできません。

Written by ufcpp

2015年2月11日 at 19:30

カテゴリー: C#

Tagged with

C# Design Notes 2/4版

with one comment

新しいC#デザイン ミーティング議事録。

今回の議題は3つ。大きいのは3つ目の Classes with values です。タプルと関連してのレコード再検討。

あっ、あと、おまけで。Roslyn の RC1 を NuGet 公開したそうです。

Internal implementation only

前にC# 7シリーズその(6)で触れた、 ImternalImplementationOnly 属性に関して、もう少し詳細な検討。

問題点に関しても前の issue ページより少し詳細に。そして、今でもできること、コンパイラーに機能追加すればできること、.NET ランタイムにも手を入れるならみたいな話と、それでどのくらい「穴」が改善するかという話がかかれています。

問題はインターフェイスに後からメソッドを足しにくい(一般にもやっては行けないこととされているし、BCL チームのポリシー的には完全にNG)ことなので、こういう属性を足す以外にも、mixins/traits って呼ばれるような言語機能の追加でも問題は回避できるかもしれません。

実際に C# 6 や 7 で、どこまでやるかや、開発ポリシーをどうしていくかなども含めて、BCL チームとの対話も必要そう。

Tuples, resords, deconstruction

その(8)で書いた通り、C#7 に向けて、タプル型も提案されたわけですが。タプル型が入ることによって、レコード型やパターン マッチングについても再検討が必要という話。

特に、タプルとレコードについて、これらの機能は一元化する方がいいかもしれないし、少なくとも統合的にデザインしていく必要があるでしょう。タプルは「レコードの特別な場合」であるべきか、もしかしたらレコードは単なる「型名のあるタプル」であるべきかなどということも考えられます。

レコードの導入動機は、値セマンティクスや immutability を持つクラスを楽に作れるようにするものなので、この辺りを次節で検討します。

Classes with values

今回出たアイディアは以下のようなもの。

要点は

  • 値セマンティクスを持つクラスは、文字通り Value 1つだけを持つ
  • Value 用の構造体を作って、それを受け取るコンストラクターを作ることで、いわゆる「ビルダー パターン」になる
  • Value はタプル型を使って定義するとよさそう
  • オブジェクト初期化子の拡張で、「wither」も簡単に書けそう

これなら確かにタプルとレコードの親和性がよく、使う側のわかりやすさ的にもコンパイラーの実装負担的にも都合がよさそう。

まあ、これはこれで、元々のレコード型の提案にあった、部分的なメンバーの置き替え(以下のようなもの)の実装が難しくなりそう。

レコードもタプルも、まだ提案の初期段階でこれから変わっていくでしょうし今後どうなるかはわかりませんが、これはこれで面白い検討内容でした。

Written by ufcpp

2015年2月11日 at 15:35

カテゴリー: C#

Tagged with