Что *так* не так с наследованием класса case?

В поисках чего-то другого, совершенно случайно, я наткнулся на несколько комментариев о том, насколько дьявольским является наследование case-классов. Там была штука под названием ProductN , негодяи и короли, эльфы и волшебники, и как какое-то очень желательное свойство теряется при наследовании классов case. Так что же не так с наследованием case-классов?


person Ashkan Kh. Nazary    schedule 22.06.2012    source источник


Ответы (2)


Это не совсем так. А это хуже лжи.

Как упоминалось aepurniet, в любом случае преемник класса, который сужает область определения, должен переопределить равенство, потому что сопоставление с образцом должно работать точно так же, как равенство (если попытаться сопоставить Point с ColoredPoint, то он не будет совпадать, так как color не существует).

Это дает понимание того, как можно реализовать равенство иерархии классов case.

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 (без переопределения равенства).

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) = ???
person user1303559    schedule 06.04.2016

person    schedule
comment
А как насчет небольшого уточнения :) ? - person Ashkan Kh. Nazary; 22.06.2012
comment
Кажется, что такая асимметричная эквивалентность была бы полезна в парадигме объектно-ориентированного программирования, точно так же, как на уровне типа ColoredPoint является Point, но не наоборот. Хотя, возможно, придется называть это как-то иначе, чем equals... может быть, subEquals? - person Luigi Plinge; 22.06.2012
comment
@LuigiPlinge, возможно, canReplace, supersedes, specifies или overrides для обратной связи? Все, что указывает на >=-ность (или >:, если хотите) этого. Мне кажется, гораздо проще назвать его с точки зрения >=, а не <=. - person Dan Burton; 23.06.2012
comment
Если подумать, такую ​​вещь было бы сложно (невозможно?) реализовать из-за возможности повышения уровня, так что, возможно, это не такая уж хорошая идея. - person Luigi Plinge; 23.06.2012
comment
Этот пример не компилируется в 2.10.2 - person expert; 03.08.2013
comment
универсальное равенство тривиально легко реализовать, чтобы удовлетворить равенство, сделать класс членом сравнения. копирование выглядит как просто ошибка, и взаимодействие с сопоставлением шаблонов должно работать, как и для иерархий классов без регистра. - person aepurniet; 18.06.2015
comment
Точно, ColoredPoint.class != Point.class? - person Lodewijk Bogaards; 15.07.2015
comment
case class получает equals только тогда, когда ни один из его родителей не переопределяет его, поэтому в этом случае ColoredPoint будет использовать equals/hashCode Point (я не знаю, было ли это уже в 2012 году), который является симметричным (и отражающим и транзитивным). Вы можете возразить, что ColoredPoint(0, 0, RED) == ColoredPoint(0, 0, GREEN) неинтуитивен, и я соглашусь, но проблема не в наследовании case-класса: у вас точно такая же проблема, если Point является классом, отличным от case, переопределяющим equals. copy больше проблема. - person Alexey Romanov; 24.08.2016
comment
Кто-нибудь может расширить этот ответ, предоставив передовое решение проблемы ColoredPoint, пожалуйста? - person ; 01.07.2017