2012-06-22 3 views
56

私は何か他のものを探していたのですが、単なる偶然の偶然のことではなく、私は邪悪なケースクラスの継承がどういうものかについてのコメントはほとんどありませんでした。 ProductNと呼ばれるこの事がありました。惨めな人と王様、エルフとウィザード、そしてケースクラスの継承によって非常に望ましい財産が失われています。なぜケースクラスの継承で間違っているのですか?大文字と小文字のクラスの継承にはどうして*間違っていますか?

答えて

97

一言:平等

caseクラスはequalshashCodeの供給実装が付属しています。 equalsとして知られている同値関係は、(すなわち、以下の特性を有していなければならない)、このように動作:全てxについて

  1. x equals xtrue(反射性)
  2. x,y,zである。もしx equals yおよびy equals zならばx equals z(推移)
  3. xの場合、y; x equals y場合、y equals x(対称)とすぐに継承階層内の平等を可能としますが、これは自明以下の例により実証される2と3を破ることができる

:その後、我々が持っている

case class Point(x: Int, y: Int) 
case class ColoredPoint(x: Int, y: Int, c: Color) extends Point(x, y) 

Point(0, 0) equals ColoredPoint(0, 0, RED) 

しかしない

ColoredPoint(0, 0, RED) equals Point(0, 0) 

すべてのクラス階層がこの問題を抱えている可能性がありますが、これは真実です。しかし、ケースクラスは、(他の理由の中でも)開発者の視点からの平等を単純化するために特別に存在するため、直観的には動作しません。は独自の目標の定義になります!


その他の理由もあります。特にcopy did not work as expectedinteraction with the pattern matcherという事実です。

+0

少し丁寧なことはありますか?:) –

+2

このような非対称の等価性は、オブジェクト指向のパラダイムにおいて有用なことであると思われます。同じように、型のレベルでは「ColoredPoint」は「Point」ですが、逆も同様です。しかし、おそらく 'subEquals'でも' equals'以外の何かを呼び出さなければならないでしょうか? –

+0

@Luigi逆関係に 'canReplace'、' supersedes'、 'specify'、' override'がありますか? '> =' -nessを示すもの(または ''あなたが好きなら ':' 'あれば)です。 '<='ではなく '> ='で表現する方がはるかに簡単です。 –

-2

これは全体的に真実ではありません。そして、これは嘘よりも悪いです。パターンマッチングが正確(ColoredPointとしてPointと一致しようとcolorが存在しないので、それが一致しません)等式として動作しなければならないので、定義領域が平等を再定義しなければならない収縮いずれの場合クラス後継でaepurnietにより述べたよう

これは、ケースクラス階層の平等性をどのように実装できるかを理解するものです。

case class Point(x: Int, y: Int) 
case class ColoredPoint(x: Int, y: Int, c: Color) extends Point(x, y) 

Point(0, 0) equals ColoredPoint(0, 0, RED) // false 
Point(0, 0) equals ColoredPoint(0, 0, null) // true 

ColoredPoint(0, 0, RED) equals Point(0, 0) // false 
ColoredPoint(0, 0, null) equals Point(0, 0) // true 

最終的には、ケースクラスの後継(等価のオーバーライドなし)でも等式関係の要件を満たすことができます。

case class ColoredPoint(x: Int, y: Int, c: String) 
class RedPoint(x: Int, y: Int) extends ColoredPoint(x, y, "red") 
class GreenPoint(x: Int, y: Int) extends ColoredPoint(x, y, "green") 

val colored = ColoredPoint(0, 0, "red") 
val red1 = new RedPoint(0, 0) 
val red2 = new RedPoint(0, 0) 
val green = new GreenPoint(0, 0) 

red1 equals colored // true 
red2 equals colored // true 
red1 equals red2 // true 

colored equals green // false 
red1 equals green // false 
red2 equals green // false 

def foo(p: GreenPoint) = ??? 
関連する問題