.NETで一般的に求められている機能のひとつに、共変戻り値型を使用可能にすることがある。例えば“virtual object Clone()”を“override Widget Clode()”でオーバーライドするような場合だ。型安全性の観点から言えば、これは完全に受け入れらるものだが、現在のC#では許可されていない。
共変戻り値型に関する提案ではこのルールが緩和され、サブクラスメソッドのメソッドの戻り値として、基本クラスのバージョンよりも具体的な戻り値型を提供できるようになる。Clone以外でも、抽象ファクトリなどのフレームワークコードの開発では便利な機能だ。
暗黙的シャドーイング
ひとつの実装案は、C#で2つの関数を発行することだ。Cloneを例に取ると、ILには次のようなシグネチャが現れる。
override object Clonable.Clone()
public new Widget Clone()
HaloFour氏によると、これが可能なのは次の理由による。
Common Language Runtimeの仕様では、オーバーライドで異なる名前と潜在的に異なる可視性を持つことは許可されているように思われます。
[…]
ILで.override節を明示的に使用することによって、オーバーロード解決の問題をすべて解決することができました。異なる可視性と名前を使用することで、オーバーライドができたのです。
コンパイラのみのこの機能はCLRの既存バージョンとシームレスに動作するので、旧バージョンのVBまたはC#でも、このようなクラスを問題なく使用することができる。
ただし、制限がいくつかある。オーバーライドメソッドによって通常は継承される属性は、新たなメソッドにはコピーされない。技術的には、コンパイラが基本クラスの属性を新しいメソッドにコピーすることは可能だが、基本クラスのメソッドに新しい属性が追加される度にサブクラスの再コンパイルが必要になるという問題がある。
また、リフレクションを使用する場合には、新しいメソッドとオーバーライドされた基本クラスのメソッドとの関係を確認することが難しくなる。
そして最後に、基本クラスインタフェースを介してメソッドを呼び出すことによるパフォーマンス面での影響がある。ただしテールコール(tail call)やその他の最適化手法を駆使すれば、軽減することは可能だ。
属性
もうひとつの実装方法は、新たな属性を使用することだ。コンパイラがその属性を理解することによって、より具体的な型へのキャストを自動的に追加するのである。
この方法の欠点は、新しい属性を解釈できない言語ではこの機能を利用できないことだ。さらに当然だが、新しい属性をBLC(Base Class Library)に追加する必要がある。つまり、すべてのプラットフォームですぐに使用できる訳ではない。
もうひとつの欠点は、構造体を扱う上で、不要なボクシング操作が必要になることだ。ふたたびCloneを例にすると、コンパイラはWdigetStructをボックスした上で、すぐに通常のWidgetStructに再びキャストしなければならない。
シャドウ/オーバーライドの緩和
この機能の代替方法は、シャドーイングのルールを緩和することである。現在は、同じメソッドをシャドーあるいはオーバーライドすることは許されていない。 ただしCLRではサポートされているので、C#では単に次のようなコードを明示的に書けばよい。
class Widget : Cloneable
{
public override Cloneable Clone()
{
return this.Clone();
}
public new Widget Clone()
{
return [...];
}
}
暗黙的シャドーイングの提案と同じく、オーバーライドするメソッドの名称の変更はコンパイラに依存している。
スケジュール
この機能に関する議論については、その大部分が2015年初頭、つまり2年以上前のものであることに注意頂きたい。提案は正式には2月に記述されているが、それ以降、すくなくとも公的には何も行われていない。
この記事を評価
- 編集者評
- 編集長アクション