C# 2.0に手を出してみる その1? Nullable Type
disclaimer: C# 2.0はまだほとんど何も知りません(あせ
僕が最近気づいたのは、僕はNullable Typeについてひどく誤解していたということだ。Nullable Typeはnullを受容することもできるようなもので、結果的にパフォーマンスの悪化に繋がるものだろうと考えていた。実際Nullable
XQueryを実装していると、たまにC# 2.0の機能を使いたくなる場面がいくつか出てくる。その典型的な例が「empty sequenceを返す」関数の実装だ。たとえばXQueryにはこんな関数がある:
fn:seconds-from-duration($arg as xdt:dayTimeDuration?) as xs:decimal?
この関数は、引数のxdt:dayTimeDurationがempty sequenceの場合にはempty sequenceという(xs:decimalではない)値を返す。empty sequenceを0.0として表現すればいいじゃん、と思われるかもしれないが、empty sequenceと0.0は、いくつかの場面において意味が異なる。
これをCLIネイティブに実装した場合*1、そのsignatureは次のようになるだろう*2:
decimal? FnSecondsFromDuration (DateTime? arg);
というわけで、XQueryを実装するにあたっては、Nullable Typeサポートは、是非ともほしい機能のひとつだ。
もちろんNullable<int>などとすれば、機能的には同等のことが実現できる。しかし、Generic Typeはoperatorが定義できないし、演算は非常にめんどくさいものになる(これについては、Eric Gunnersonの説明の後半にある、int? x + int? yの説明を読んでもらえれば分かると思う。int?は、そんなに単純なsyntax sugarではなく、もっと複雑な考慮がはたらいている)。
.NETのGenericsに演算子オーバーロードが無い問題については、OSNewsに投稿された記事でも、解決策が提案されていて、monoのSystem.Int32を使った実装もある。うちのMiguelは関心を示しているようだ。どうやらC# 2.0ではこの辺はサポートされないようだけど(今からこんな追加してたら、ただでさえ遅れているWhidbeyがリリース出来なくなっちまう)。Eric Gunnersonは、これを受けて(というかヘジたんのヒントをもとに)別のアプローチを提示している。これもスマートですな。
…でもちょっと突っ込んだ話になると、まだ面倒な部分はある。
まずakirameiさんの実験がとても勉強になる。cscではこの辺(定数との演算とか)うまくやっつけているのだろうか。
もうひとつ問題だなと思ったのは、先のEric GunnersonのエントリにPortable.NETのThong Nguyenがコメントしている、boxing/unboxingとの関係と、asの問題*3:
これは単にcscが未対応というだけかな? いずれにしても、Martin Bauligに安易にお願いできるような簡単な機能ではないようだ(Nullable Typeはまだgmcsではサポートされていません)。
int? x = null;
object y = x;
int? z = y as int?;