C# で 劣化 Variant を書いてみた (2)
id:NyaRuRu:20080519:p1 にちょっとだけ続き.
Generative Programming より
多重定義の機能は、多くの静的な型づけ言語が備えています (例えば、CとPascalは多重定義をサポートしませんが、C++とJavaはサポートします)。多重定義はすべての引数の型を使って異なる実装を区別しますが、戻り値の型は使わないことに注意して下さい。通常、多重定義では (オーバーライドにおいても) 戻り値の型についてはサポートしません。なぜなら、関数は「単なる副作用」としても呼び出せるからです。例えば、
foo();これは、次の代用です。ResultType temp = foo();戻り値の型だけが異なる実装が複数用意されていたとき、前者の呼び出しではコンパイラ (もしくはランタイムシステム) はどの実装を呼び出すべきなのかが判断できません。
まあそういう意見はあるよなぁと思いつつ,「導入できない理由」と「導入しない理由」ってのは違うよなぁという気も.曖昧なときはコンパイルエラーという場面は他にもあちこちありますし.(といいつつ別に C++ や C# に欲しいというわけじゃないんですが)
んでは次のはいかが?
template なキャスト演算子と左辺から右辺の推論
GetProcAddressで戻り値をキャストするのが面倒くさいので少し考えてみた
こんな感じでどうでしょう。
struct ProcAddress { ProcAddress(HMODULE module, LPCSTR name) : p_(0) { p_ = ::GetProcAddress(module, name); } template<class T> operator T() const { return reinterpret_cast<T>(p_); } FARPROC p_; };こうやって使います。
HMODULE module = 0; typedef void (__stdcall *Func)(); Func f = ProcAddress(module, "test");
これの特殊版が前回の『C# で 劣化 Variant を書いてみた - NyaRuRuの日記』ですな.
ようするに implicit な型変換が登場する場面では,逆方向の推論っぽく見えるという感じでしょうか.C# の method groups から delegate への implicit conversion もこのタイプですな.
プログラミング言語 merd
k.inaba さんの紹介記事 が参考になります.とてもかっちょいいです.
ad-hoc overloading
上のように関数の引数として渡せると言うことは、 単純な「名前が同じに宣言された関数を、多重に扱う」という処理ではなく、「複数の実体がオーバーロードされている値」 という特殊な値を言語的に扱っている、ということを意味しています。
つまり、「この値とこの値を多重に重ねたい!」と思ったら、 その場でコードとして書くことができます。例を見てみましょう。 |&|演算子を使います。
x = 1 |&| "one" x.println (x + 3).to_string.println"one" 4.使われている場所に応じて数の 1 だったり文字列 "one" として扱われる値、x を定義しています。
こういうのを見ていると,「こんなにも・・!! こんなにも苦しいのならば型などいらぬ!!」っていわれるほど静的型は嫌われなくてよいのになぁ,とか思ったり.