Marekのmcs warning hackingはしばしばcscの一歩先を行っている。今日ネタになっていたのはこんな感じのコードだ:
public class Class1
{
public virtual void Foo () {}
}
public class Class2 : Class1
{
[Obsolete]
public override void Foo () {}
}
.NET 1.1/2.0のcscではwarning対象とされないが、このようなObsoleteAttributeの使い方には問題がある(オーバーライドされた方のメンバーを参照した場合のみwarningが出るのでは一貫性に欠ける)。最近のmcsではちゃんとレポートしてくれるようだ。
追記: 次のバージョンのcscでは同様の警告を出すようになる、とMarekは書いている。たぶんMSのproduct feedbackの返事か何かでそう言われたのだろう。
コメント
ladybug — 01/08/2007 09:21:12
抽象クラスからの汎用的なパラメータによる実装ポイントをobsoleteして、具現クラスで具体的パラメータによる overload を提供する場合、具現クラスのメソッドにだけ obsolete を出したい場合って、ありませんかな?
atsushieno — 01/08/2007 09:50:54
具象クラスが何になるかは、抽象クラスを用いた呼び出しにおいては決定できないので、やはりparams付きメソッドであってもobsoleteは一貫性を欠くことになると思いますが、そういう話ではないですかね?
ladybug — 01/08/2007 10:34:21
class ObsoleteAttribute : WarningAttribute みたいなかんじで WarningAttribute の派生クラスで遊べたら、色々困らないのかなあ。
ladybug — 01/08/2007 10:48:01
最初のコメントのは、
abstract class Class1
{
public abstract void Foo(object o);
}
public class Class2 : Class1
{
[Obsolete(”call Foo(int)”)]
public override void Foo(object o) { Foo((int) o); }
public void Foo(int v) { … }
}
object o = …;
Class1 formatter = GetFormater(o.GetType());
formatter.Foo(o);
は無警告だが、
Class2 intFormatter = new Class2();
intFormatter(o);
は、警告したい、みたいな。(Obsolete の仕事じゃない)
atsushieno — 01/08/2007 11:05:00
派生クラス
意図がよく分かりませんが、BlahAssembly::BlahNamespace.ObsoleteAttributeを対象にすることはないと思います。
具象クラス
Class1 formatter = new Class2();
formatter.Foo(o);
となっていると警告されないわけで、まさしく一貫性に欠ける例であると思います。
ladybug — 01/08/2007 12:32:48
抽象的なインターフェスに対して抽象的な操作 → 警告なし
具体的なインターフェスに対して具体的な操作 → 警告なし
抽象的なインターフェスに対して具体的な操作 → コンパイルできない
具体的なインターフェスに対して抽象的な操作 → コンパイルできるが警告あり
というかんじで、Class1 formatter = new Class2() で警告されないなら、狙い通りってことですね。
ladybug — 01/08/2007 12:44:37
逆(ObsoleteしたメソッドをoverrideしてObsolete消せる)ができちゃうのはマズいと思うけど、たしか警告されますよね。
これは Obsolete じゃなくて WarningAttribute みたいなのが出来ても一緒だとおもうのですが。
ladybug — 01/08/2007 13:07:14
派生クラスは、親クラスに対して設計と実装を変化させることができますが、実装の変更は親クラスとしての動作にも影響を与えますが、設計の変更は親クラスとしての設計に影響を与えてはならない、というかんじかな?
親クラスで設計されたメソッドに、派生クラスで Obsolete という設計の変更がはいっても、それが親クラスとして扱われるかぎり影響しない、というのが OOP の契約関係じゃないのかなあ。
ladybug — 01/08/2007 13:21:26
OOPの〜 というと変なきがしてきた。Perl や JavaScript みたいな prototype な OOPL だと設計に対する影響もだせるし、CLASS 型の OOPL に特異なことか。
atsushieno — 01/08/2007 15:02:16
設計の変更は親クラスとしての設計に影響を与えてはならない
はい、そんな感じの意図です。
WarningAttributeって、現存しないのですが、単に任意の属性を基底クラスとする、名前がObsoleteAttributeになるような属性ではなくて、一部コミュニティで「こういうのがあったらいいなー」って言われているもののことですか? ObsoleteAttributeはsealedなので、警告を生成できる属性も同様に、sealedでなければならない、という制約があれば問題にならないと思います(既にObsoleteAttributeで実現されている規則なので、不自然な制約には思えません)。
契約関係
これは、宗教的に争いの余地があるような気がしますが、契約関係というものが↑のようなものであったとしても、IsError=trueであるようなObsoleteメンバーを、書き方次第で呼び出せてしまっても、契約関係でそういうことにはなっていないから問題ない、と言えるほど重要ではないように思えます。