読者です 読者をやめる 読者になる 読者になる

整数型に対する Compare の実装 (2)

.NET

(追記その 3)
すみません.派手に勘違いしていました.
Int32 は IComparable<T> を明示的にではなく通常の方法で実装していますし,CompareTo(int value) はパブリップメソッドとして公開されています.4649.CompareTo(x) は普通に書けます.

static int HardCmp(int x, int y)
{
    return (x == y) ? 0 : (x > y) ? 1 : -1;
}

は,

static int HardCmp(int x, int y)
{
    return x.CompareTo(y);
}

のように書くことが,実際に可能です.



(追記)
前回のネタ『[.NET]整数型に対する Compare の実装』へのリンクが切れていて意味不明なエントリになっていたのを修正しました.

追記:.NETは関係ないよ。32ビット整数と64ビット整数を持つ処理系の話だ。手元でcscがすぐ動く環境でたまたま書いてたからC#で書いてるだけ。でもまあ、おもしろいので『整数型に対する Compare の実装』も参照すると良いかも。(さらに追記:ああ、意図がわかったかも。正しい実装(HardCmp)については自分で実装しなくても良いってことか。まあ、それは実装の比較ということでというか.NETの実装を使ってはあまり意味がない、と多分NyaRuRuさんはわかってるので別の話を展開して、というのが流れか)

については,最初はコメントを書こうと思ったらエラーで書けなかったので,適当にエントリ形式に仕上げたとかその程度の意図です.結局トラックバックも失敗しているっぽいですが.
個人的には C の qsort みたいに 3 値を返すことを要求する比較処理より,STL の std::sort みたいに 2 値ですむ比較処理の方が好きで,.NET が何で qsort の暗黒面をパクったのか謎に思うことしばしばです.って書いててもしかしてインライン展開できないからメソッド呼び出しの回数減らしたかったとかそういうオチかという気がしてきましたが.
まあ結論としては C# 2.0 で 4649.CompareTo(x) みたいに書けないことでいったい誰が幸せになっているのでしょうか,みたいな.
(追記 その3)すみません,普通に書けました.



arton さんのところで,どこかで見たような .NET の比較述語ネタが.
比較しないのは難しい


以前『[.NET]整数型に対する Compare の実装』で System.Collections.Generic.Comparer<T>.Default の使い方の話は書いちゃったので,むしろ Comparer<T>.Default をどうやって作るかの方向の話でも.
IntelliSense に表示されないので気付きにくいですが,Int32 は明示的に実装されたいくつかのインターフェイスを備えていて*1その中に IComparable<T> というそのものズバリなインターフェイスが存在します.なので,本当は Int32 の比較処理を再実装する必要はありません.
ただし,単純に値型を IComparable<T> にキャストしてしまうと boxing が発生し,比較のたびに GC ヒープが消費されてしまうためうれしくありません.そこで,ジェネリックメソッドを使って boxing を回避しましょう*2.結論としてはこんな感じ.

static int HardCmp<T>(T x, T y) where T : IComparable<T>
{
    return x.CompareTo(y);
}

delegate だけでいいならこういうのでも.

static Comparison<T> GetHardCmp<T>() where T : IComparable<T>
{
    return delegate(T a, T b) { return a.CompareTo(b); };
}

ここまで書けば,Comparer<T>.Default のからくりも見えてくるのではないでしょうか.実際どうやって作るかは次回までの宿題ということで.



(追記その 2)
上のコードは第 1 引数が null だったときの挙動が .NET のセマンティクスと合致しないので,参照型に対しては使えません.これらを正しく考慮するにはこうします.

static int HardCmp<T>(T x, T y) where T : IComparable<T>
{
    if (x != null)
        return y != null ? x.CompareTo(y) : 1;
    else
        return y != null ? -1 : 0;
}

値型は絶対に null にならないので,JIT コンパイラは不要な比較を排除してくれます*3.参照型と値型でコードを分ける必要はありません.
この手のコードを何回も書くのが面倒というのであれば,Comparer<T>.Default を使用すると良いでしょう.修正版のコードでも Nullable<T> に対応していませんが,Comparer<T>.Default は Nullable に対しても使うことができます.



ちなみに(追記) .NETこういう話はとりあえずこれ一冊読んでおけばなんとかなります.未読の方は是非どうぞ.
プログラミングMicrosoft .NET Framework 第2版 (マイクロソフト公式解説書)

プログラミングMicrosoft .NET Framework 第2版 (マイクロソフト公式解説書)

*1:プログラミングMicrosoft .NET Framework 第2版』「14.10 インターフェイスメソッドの明示的実装に関する注意」

*2:プログラミングMicrosoft .NET Framework 第2版』「5.3 値型のボックス化とボックス化解除」

*3:プログラミングMicrosoft .NET Framework 第2版』「16.8.4 その他の検証可能性に関わる問題」