Roslyn 開発版でC#7を触る


[Roslyn もくもく勉強会](https://eventdots.jp/event/594178)の記録。

Roslyn は活発に開発中のため、言語仕様含めて随時更新される。
内容は8/6（土）現在のものがベース。
あまり込み入った記述をするとエディターが落ちるので注意。


## 必須環境

- Visual Studio 2015（Update 2以降）
- VS拡張性ツール インストールしていない場合はコントロールパネルの「プログラムと機能」から修正する。
- コードアナライザなども試したければ [.NET Compiler Platform SDK](https://visualstudiogallery.msdn.microsoft.com/2ddb7240-5249-4c8c-969e-5d05823bcb89) もいるはず（未確認）。


## 準備


Gitでリポジトリを取得。

```dos
git clone https://github.com/dotnet/roslyn (your folder)
```

Visual Studio 開発者コマンドプロンプトを起動し、取得先のフォルダに移動。

```dos
cd (your folder)
```

下のコマンドを実行。Nugetの更新やパッケージの取得が走る（10分くらいかかる）。

```dos
restore.cmd
```

下のコマンドを実行してビルド（これも10分以上かかるはず）。

```dos
msbuild /v:m /m Roslyn.sln
```

Visual Studio でRoslyn.sln を開く。

ソリューションをビルドする。

Binaries フォルダ以下に VisualStudioSetUp.visx が生成されれば一安心。

VisualStudioSetUp をスタートアッププロジェクトに指定してF5で実行する。


独立した Visual Studio のインスタンスが起動するので、そこでコンソールアプリケーションプロジェクトを作成する。

### 参考

ほぼ下のリンクの通り。

- [Building, Debugging, and Testing on Windows](https://github.com/dotnet/roslyn/blob/master/docs/contributing/Building,%20Debugging,%20and%20Testing%20on%20Windows.md)

## Let's code!

現時点で使える機能は以下の通り。

- Binary Literals
- Digit Separators
- Local Functions
- Type Switch
- Ref Returns
- Tuple Syntax
- Out Var
- ValueTask


詳細と最新のステータスは [Language Feature Status](https://github.com/dotnet/roslyn/blob/master/docs/Language%20Feature%20Status.md) を参照。


……ただし。
関数の戻り値で Tuple Types を使うとコンパイルエラーが出るので、一点だけ追加の準備が必要。

1. [`System.ValueTuple`](https://github.com/dotnet/corefx/tree/master/src/System.ValueTuple) を nuget でプロジェクトに追加するか、
2. Roslyn のフォルダの src/Compilers/test/resource/ のなかの System.ValueTuple.dll の参照を追加する


## 新機能について諸々

きちんとした内容は主催者でもある [岩永氏のブログ](http://ufcpp.net/blog/2016/8/pickuproslyn0810/)を参照。

### Binary Literals


２進数リテラル。 `0b` または `0B` から定数値の記述をはじめると２進数表記が使える。


### Digit Separators


整数値リテラルを `_` で区切ることができる。 `0b_1100_1111` のようにして使う。


### Local Functions


ローカル関数。つまり関数内関数。

デリゲートやラムダ式と同じで周囲の変数をキャプチャできる。

### Type Switch


文字どおり、switch 文を型＋変数で分岐させるもの。

型のみを対象としたパターンマッチングの一部。

switch だけでなく、 is 演算子も予定されている。
これができると下のコードが、

```csharp
var s = x as string;
if (a != null) {
  return int.Parse(s);
}
```

下のようにかける。intのような値型でも統一的に使える点で as 演算子よりも優れている。

```csharp
var s = x as string;
if (x is (string s)) {
  return int.Parse(s);
}
```


#### 覚書：


ILレベルでは予想通り if + as にコンパイルされるので、
現時点では単なるシンタックスシュガー。


### Ref Returns


戻り値とローカル変数で `ref` を使えるようにするという話。

もともとの `ref` の意味からは外れるが、
構造体の受け渡しのオーバーヘッドをなくしたり、
アンマネージドコードのポインタを返す関数を受け取ったりする要望に応えたもの。

### Tuple Syntax


タプルまわりのアップグレード。
LL的な書き心地ももちろんあるが、`async/await`構文のために関数の **多重戻り値** のサポートが必要になったのも大きいだろう。


具体的には以下の3つの小機能からなる。


1. タプル型サポート。関数の戻り値などで名前付きタプルを定義できる。
2. タプルリテラル。タプル生成（やパターンマッチング）のための専用記法が導入される。
3. タプル分解。タプルを要素に分解して変数で受け取れる。言語によっては多重代入と呼ばれる。

全部使うと以下のようになる。

```csharp
public static void Main(string[] args)
{
   var t2 = Divide(2, 3);
   Debug.Assert(t2.quotient == q); //名前によるアクセス。
   Debug.Assert(t2.remainder == r);
   
   (var q, var r) = Divide(2, 3); //タプル分解
   Debug.Assert(q == 0);
   Debug.Assert(r == 2);   
}


public static (int quotient, int remainder) Divide(int lhs, int rhs) //タプル型戻り値。
{
   return (lhs / rhs, lhs % rhs); //タプルリテラル。
}
```

#### 補足

名前によるアクセスはコンパイラにしか見えない擬似的なフィールド。
ILのレベルではプレーンな `System.Tuple` と変わらず、
単に `TupleElementNamesAttribute` という属性で名前を与えている。
なので、リフレクションや式木で扱うときは注意がいる。

分解の対象はタプルに限らない。
仕様は揺れているが、拡張メソッドを含めて特定の名前と形のメソッドを提供してさえいればどんなクラスでも適用できるようになる予定。
イメージとしては演算子オーバーロードに近い。

### Out Var


`out` で変数を受け取るときに `var` で変数を定義するという話。
要するにこれが


```csharp
var dict = new Dictionary<string, string>();
string value; //NOT var
if (dict.TryGetValue("none", out value))
{
  ...
}
```


こうなる。

変数のスコープが「はみ出ない」ことにも注目されたし。
 
修正されました。単純に外側の `{}` ではなく、説明すると少し複雑になる。


```csharp
var dict = new Dictionary<string, string>();
if (dict.TryGetValue("none", out var value)) //YES! var
{
  ...
}
```


### ValueTask

1. Arbitary async returns ... 現状の `async` メソッドでは `void`/`Task`/`Task<T>` しか使えないところを、Task-likeなクラスであればなんでも利用できるようにする。
2. ValueTask ... 実際に `Task` を使わない場合は効率的に動作する `ValueTask` 型を提供する。

という話で、言語機能の変更としては 1 が大。

Task-like は構文だけあっていればインターフェイスなどは不要（いわゆる structural typing）。
なので、今後、拡張メソッドの static メソッド対応（static extension methods）が実装されると
既存の独自の「非同期」型でも `async/await` が使えるようになると期待されている。


## その他


ある程度、新機能を追っているひとへ。

- ここ一箇月くらいで Record 型が先送りになりました（2016/6頃）。あわせて With 構文も。
- パターンマッチングはほぼ先送りで、Type Switch のみが先行導入された形。
- 各種の文（statement）の式（expression）化も先送り。合わせて throw 式も先送り。

なお Visual Studio 15 Preview での実装状況については以下を参照のこと（8/24時点）。
https://blogs.msdn.microsoft.com/dotnet/2016/08/24/whats-new-in-csharp-7-0/