ものがたり(旧)

atsushieno.hatenablog.com に続く

C# 2.0に手を出してみる その1? Nullable Type

disclaimer: C# 2.0はまだほとんど何も知りません(あせ

僕が最近気づいたのは、僕はNullable Typeについてひどく誤解していたということだ。Nullable Typeはnullを受容することもできるようなもので、結果的にパフォーマンスの悪化に繋がるものだろうと考えていた。実際NullableのようなGeneric Typeに置き換えられるので、パフォーマンスが良いわけではないだろうけど、boxing/unboxingがかかる1.xに比べればずっと優れた機能のはずだ。と、前置きはそのくらいにして…

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


int? x = null;
object y = x;
int? z = y as int?;
これは単にcscが未対応というだけかな? いずれにしても、Martin Bauligに安易にお願いできるような簡単な機能ではないようだ(Nullable Typeはまだgmcsではサポートされていません)。

*1:何でCLIネイティブに実装するのか?についてはこの前書いたので、そちらを見て下さいな。

*2:ちなみに、MS.NETのMS.Internal.Xml.XQueryFuncLibraryには、該当するメソッドがまだ定義されていない。

*3:nullable.cs(9,12): error CS0077: The as operator must be used with a reference type ('int?' is a value type)