C# constraints on type parameters

まず C# library 用 git repository を作った。

そして http://d.hatena.ne.jp/janus_wel/20101129/1291047346 で書いてた Pair<> を突っ込んでみた。

前回からの変更は以下。

IEquatable<> から CompareTo() method を継承して実装したところが変わってる。これの何がうれしいかというと以下のように comparator なしで sort できるようになる。要は sort の default の振る舞いを定義したわけだ。

using System.Collenctions.Generic;
using Utility.Data;

// omit

// sort test
List<Pair<int, int>> list = new List<Pair<int, int>>();
list.Add(new Pair<int, int>(2, 2));
list.Add(new Pair<int, int>(3, 4));
list.Add(new Pair<int, int>(2, 3));

list.Sort();

Debug.Assert(list[0].Equals(new Pair<int, int>(2, 2)));
Debug.Assert(list[1].Equals(new Pair<int, int>(2, 3)));
Debug.Assert(list[2].Equals(new Pair<int, int>(3, 4)));

ここまではいい。で、これを実現するためには「型引数の制約」て概念が必要になるんだけどそこにあたるのが https://github.com/januswel/cslib/commit/b04f20bd1d05697f790aed080c243ddfffaa66c3 の 19, 20 行目で追加されてる where なんたらとかいうやつ。

ここで出てくる where は SQL の where と同じような意味で、条件をあらわす感じ。 LINQ といい、けっこう C#SQL 好きらしい。で、指定できる条件には http://msdn.microsoft.com/ja-jp/library/d5x73970.aspx に挙げられているものがあるんだけど要は型引数に指定した型がどういう型であってほしいかを指定してるだけ、と。 default constructor を持ってて object を構築できるとか、ある class から派生しているとか、ある interface を実装してるとか。

今回は、

  1. Pair<> の CompareTo() の実装に T 型と U 型の CompareTo() を使いたい
  2. つまり T 型と U 型が CompareTo() を実装していなければならない
  3. CompareTo() を interface として定義しているのは IComparable<> だ
  4. てことは T 型と U 型はそれぞれ IComparable<> interface を実装していてほしい
  5. 最終的に「型引数の制約」として T : IComparable<T>U : IComparable<U> がくっつく

とまぁこういう流れで where ってる。

ここらへん C++ だと型引数に指定された型にできない操作をするとちゃんと compiler が怒ってくれるんだけど複雑なことやってるときは正直何が悪いのか気づきにくい diagnostic message なんだよな。うーん、「標準 interface 」と「型引数の制約」という人間にとってわかりやすい概念でちゃんと型の間の関連を記述できる、というのは C# の advantage かも。

なんかおれ C# に毒されてないか… ? まぁ test code だけど C++ をさらっと書いてかかっと command line compiler をたたけたのでまだ染まりきってないとは言える。…あまり芳しくない。