Unit 型の存在しない C#,たったひとつの冴えないやり方

菊池さんのリバーシネタで思い出しました.

Unit 型が無くて困るぜな話.

letで代入を伴うのでvoidなメソッドを呼べないといってintに変えてまでどっぷり暗黒面という事で、「その気になればif、for、foreach、whileといった制御構文みんな要らないよね」ではありますが適度に使ってくれたほうが絶対良いですね。

re: LINQでリバーシ(4) そして暗黒面へ 2008/02/07 9:40 菊池 - 菊池 Blog

これについては,

"voidを返すメソッド() is object"でboolを表現できる

素数を求める1行プログラム(C#3.0編) - このブログは証明できない。

ってのを最近見て「へーへーへー」だったのでありますよ.

var q = Enumerable.Range(0, 100)
                  .Select(i => !(Console.WriteLine(i) is object) ? i : i)
                  .ToArray();

という感じで副作用挟み込み.警告鬱陶しいですが.

追記

そういや警告 CS0184 は嫌な予感がするなあと思ったら予想通り嫌なことになっていた.
CS0184 should be a compile error

C# にて副作用は必要だが戻り値が void で困った場合にどうするか? - NyaRuRuが地球にいたころ

Unit 型が存在しない C# では,戻り値 void のメソッドだけ特別扱いしないといけなくて何かと面倒なのですが,実はメソッド呼び出しの後に "is object" と書いて「コンパイル時計算」させれば,戻り値 void のメソッドを式に組み込めるというダークサイド技があります.が,暗黒面たっぷりゆえに罠もあって,そのコードを Expression Trees に取り込んで,Compile メソッドを呼び出すと不正な IL コードが出力されるという暗黒面畳返しがありました (Visual C# 2008 RTM 版の話).
とまあそんな話だったのですが,最近リリースされた Visual Studio 2008 SP1 beta1 で試したところ問題は fix されているようです.

Func<bool> func =
    () => Console.WriteLine("hauhau") is object;
Expression<Func<bool>> expr =
    () => Console.WriteLine("hauhau!") is object;

Console.WriteLine("func: {0}", func());
Console.WriteLine("expr: {0}", expr.Compile()());

実行結果

hauhau
func: False
hauhau!
expr: False

Expression Trees 的にも (an_instance_of_void) is object が false で確定したというのは意味深というかなんというか.それとも null is object が false なのの同類と納得すればいいのでしょうか.
まあ最初から C# に Quoting が導入されると分かっていれば,C# 1.0 で is 演算子をこんな振る舞いにはしなかったと思いますけどね *1.Quoting を導入し,かつ複数の言語で共有する AST に変換されかねない場合,コンパイル時に変な計算はやらない方がベターなんでしょうな.以下の問題は解決されそうにない気がします.

Func<bool> func =
    () => new DayOfWeek[7] is int[];
Expression<Func<bool>> expr =
    () => new DayOfWeek[7] is int[];

Console.WriteLine("func: {0}", func());
Console.WriteLine("expr: {0}", expr.Compile()());

結果

func: False
expr: True

*1:意味がよく分からない人は『CS0184 should be Compiler Error - Microsoft Connect』をどうぞ.ややこしい .NET の Assignment Compatibility については『Assignment Compatibility - NyaRuRuの日記』に以前まとめたものがあります.