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

http://ufcpp.net/

Archive for 8月 28th, 2014

Visual Studio 14 CTP 3でのC# vNext

leave a comment »

先週、Visual Studio 14 CTP 3が出たわけですが、ようやくだいぶ触れました。個人的な感想としては、だいぶRoslyn (新しいC#コンパイラー、C# vNext)が安定してきたなーという感じ。なので、その辺りの話というか、Connectに報告出してたバグも結構直ってたという話。

CTP 3でのC# vNext

C# vNext (いずれC# 6.0になるだろう仕様)の現状については、以下のディスカッション ページを参照。

C# vNextは、仕様が固まっていない機能も多いし、新機能もいくつか追加されていってるし、仕様だけあるけども実装がないものもまだまだあって、バージョンアップのたびに新しい実装が追加されています。今回のCTP 3では、以下の3項目が上がっています。

  1. The nameof operator – safe strings for named program elements, such as variables, types, members etc.
  2. More expression-bodied function members – concise member bodies to avoid boilerplate when things are simple
  3. Null-conditional statement expressions – easy null check when you raise events

nameof演算子(nameof operator)

1つ目については、わかりやすく「便利な新機能」なので、仕様書(案)の該当する章を眺めてみてください。ほしい場面結構あった。

以下のコードのように、変数やメンバーを与えて、その変数名/メンバー名をstringで取得するもの。デバッグ用のログや、PropertyChangedの実装に便利。

static double CheckedSqrt(double x)
{
    if (x < 0) throw new ArgumentException(nameof(x) + ” must be positive”);
   
 return Math.Sqrt(x);
 
}

式形式の関数(expression-bodied function)

2つ目は、「式形式の関数メンバー」の対応。これは、仕様書上は結構初期からあったものの、やっと実装が来ました。

以下のコードのToStringメソッドとか、Lengthプロパティ(のgetter)とかみたいな書き方。

using System.Math;

class Point(int x, int y)
{
   
public int X { get; } = x;
    
public int Y { get; } = y;
 
  public override string ToString() => “(“ + X + “, “ + Y + “)”;
  
 public double Length => Sqrt(X * X + Y * Y);
}
 

null条件付きのステートメント(Null-conditional statement expressions)

null伝搬メンバー アクセスはCTP 2の段階で入っていたはず。以下のような、. の代わりに ?. を使うことで、左辺がnullだったら結果もnull、nullでなかったらメンバーの値を返すもの。

static int? GetPX(LineSegment line) => line?.P?.X;

で、たぶん、今回追加されたのは、これのvoid版ですかね。左辺がnullでないときだけ、戻り値のないメソッドを呼び出し。

イベント発生コードの実装が楽になるとのことなので、たぶん、以下のような使い方を想定しているのではないかと。

public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged([CallerMemberName] string propertyName = null)
    
=> PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
 

バグ修正

というような新実装に加えて、いくつかバグが取れてだいぶストレスなく使えるようになってました。というのが今日の本題。

「タブの保持」のときのコード整形

今関わっているプロジェクト、歴史的経緯で、インデントを「タブの保持」設定にしてるんですよね。で、この設定下でドキュメント コメントとかを入れようとすると、整形がうまくいっていませんでした。

以下のようなずれ方。タブが入らない。確かCTP 2の時はこのバグ残ってて、今回やっと修正。

宣言式(declaration expression)で作った変数のスコープ、その1: ifステートメント

(これはCTP 2の時点で治ってたかも)

以下のようなコードで、ifステートメントの中で宣言したxのスコープはどこまでかという問題。

using System.Console;

class Base { }
class A : Base { public int Value { get; set; } }
class B : Base { public string Name { get; set; } }

class Sample
{
  
 public static void DeclarationInIfConditionScope(Base b)
    {
        if ((var x = b as A) != null) { WriteLine(“A: “ + x.Value); return; }
       
 if ((var x = b as B) != null) { WriteLine(“B: “ + x.Name); return; }
       
WriteLine(“Base”);
    }
}
 

宣言式で作った変数は、その後ずっと使えます。その式の直前で変数宣言したのとほぼ同じ結果に。

とはいえ、じゃあ、こういうifとかwhileのかっこの中で作った変数はどうあってほしいかというと、そのif-elseや、whileの内部でだけ使えた方が嬉しい。for (var i = 0; i < N; ++i) みたいなののiはforステートメント内でしか使えませんし、それと同列。

ちょうど上記のコードが好例ですが、ちょっと前のRoslynプレビューまでは、このコードは「xが2回宣言されている」ってエラーが出てコンパイルできませんでした。CTP 3ではできるように。

その2: ラムダ式

同様の問題、ラムダ式でも。

前のバージョンでは以下のようなコードも、「xが2回宣言されている」エラー。

Func<string, int?> f = s => int.TryParse(s, out var x) ? x : default(int?);
Func<string, double?> g = s => double.TryParse(s, out var x) ? x : default(double?);
 

というか、変数xはラムダ式の外側で宣言されている扱いになって、「ローカル変数のキャプチャ」が発生するようなコードに展開されていました。

さらにいうと、フィールド初期化子でのラムダ式代入だと、(xが2個なくても)1発アウトでコンパイル不可でした。

CTP 3では、以下のような意味になるよう修正。

Func<string, int?> f = s =>
{
   
 int x;
   
 return int.TryParse(s, out x) ? x : default(int?);
};
 

その3: 式ツリー

ラムダ式中の宣言式で前述の問題があったという前提の元、以下のコードを見てください。

Expression<Func<string, int?>> f = s => int.TryParse(s, out var x) ? x : default(int?);

前は、これが残念な感じでコンパイルが通ってました。ローカル変数をキャプチャした状態のラムダ式が生成されてるので、匿名クラスのcompiler-generatedな謎のフィールドを参照している式ツリーが作られる。

まあ、CTP 3ではちゃんとエラーに。前述の通り、CTP 3での「ラムダ式中の宣言式」の展開結果は、式ではなくなってしまうので。

意外と

というように、単純そうに見える新機能も、やってみると意外とはまるところがあって、案の定、挙動に問題があった。で、やっと治った。

まあもちろん、CTP (あくまで早期プレビュー版)なので毎度のことではあるんですが。今回(そしておそらく今後はずっと)、かなり早い段階での仕様の公開や、オープンソース開発への移行で、こういう過程がよく見えるようになったのが少し面白かったり。

とはいえ、今回、CTP 3でだいぶ安定してきたように感じていたりします。そろそろ、ufcpp.netに「C# 6.0」のページ作ろうかな(今まで作ってなかったのは、まだ仕様が緩くて変わったり、やっぱなくなったりがあるのわかってたから)。

Written by ufcpp

2014年8月28日 at 23:49

カテゴリー: C#

.NET vNext

leave a comment »

先月の夏サミのコミュニティオープンジャムと、こないだのこみゅぷらすで.NET vNextの話ちょこっとしてきた。

4月の//build/と5月のTechEd NAの内容がベースなので、旬は外し気味。

.NET vNext from 信之 岩永

Written by ufcpp

2014年8月28日 at 01:14

カテゴリー: .NET