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

http://ufcpp.net/

Archive for 8月 2014

C#に型パターン マッチング

with one comment

前の記事のおまけで「さらに将来の話」。

以下のような仕様も入りそう。

関数型言語でよくあるような、レコード型に対するパターン マッチングがC#にも入りそう。

これは、VS 14 CTP 3でまだなだけじゃなくて、Roslynのコード リポジトリ上も、masterブランチにはまだとりこまれていない機能。pattern-matchingっていうブランチがあって、まだそこの上でだけ動いてる模様。

このリポジトリ上の、テスト コードとかを覗いてみると、現状どんな文法になっているのかわかる(仕様書ドラフト中のサンプル コードはこれの一部な気がする)ので、そのコードの場所だけ貼っておきます。

  • コード リポジトリで、「Browsing changes in」のところで「pattern-matching」ブランチを選択
  • Src/Compilers/CSharp/Test/Semantic/Semantics/PatternMatchingTests.cs でフォルダー階層をたどる

Written by ufcpp

2014年8月29日 at 00:02

カテゴリー: C#

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

バフ

leave a comment »

今日は、「みんな言葉の意味とか考えずに使うし、それがそのまま定着しちゃう」という愚痴の話。

「バフかけます」

仕事的に、ここ数年RPG的なネトゲに関わってて、そこで常々意味の分からない言葉が1個あります。「バフ」。何かよくわからないんだけども、ベテランほどよく使う。

その言葉が今現在どういう意味で使われてるかは流石に調べりゃ出てくるんですが。バフはおおむね以下のような意味で使われます。

  • 【バフ】パラメーター増減系のサポートスキル。味方が有利になるサポートをバフ、不利になるものをデバフとか呼んだりする。

でも、これが元々何の略語かとか、単語の本来の意味は何かとか、いつからこんな意味の単語できたのかとか、誰も知らないんですよねぇ。MMO方面から来てるということまでは分かったものの、MMO歴10年越えのベテラン廃人プレイヤーすら、元の意味知らずにバフって単語を使ってたり。

いい加減気になってよくよく調べてみたら、元々の言葉は「ダメージバッファー」らしいです。ダメージを減らす緩衝材(buffer)。これを略してバフ(buf)。そして元の意味が失われた結果、サポート全般を指してバフと言うように(しかも、「バフをかけてくれる人」を指してbufferって呼んでたり)。割かし、「Wikipediaをwikiと略す」に通ずる酷さが。まあ、他に短い音で的確に言い表す単語もない(サポートとかだと、回復なんかも含まれる印象ある)んで、定着しちゃうのも仕方がない感じはします。

でも、初心者にはやさしくない。一体何人から「バフって何ですか?」って聞かれたか分からない。意味の分からない単語で会話してるグループに入って行くのって怖いですしね。結構、初心者の離脱ポイントになっているような。

仕事でもバフかけてません?

まあ、特定分野のゲームの話でしたが。割かしどこの世界でもある話なのがなんとも。語感がいいから業界内で定着してしまった謎の用語。元の意味から離れてしまい字面から語源が分からない。謎の単語で会話するベテラン。首をかしげる若い人。「こんな常識的な言葉から教えないと行けないのか」とか機嫌悪そうにするおっさん。

Written by ufcpp

2014年8月7日 at 21:22

カテゴリー: 未分類