scala - May mix-in traits extend case classes from a technical perspective? -
i read repeatedly on case classes shall not extended because case class implements equality method default , leads issues of equality. however, if trait extends case class, problematic?
case class mycaseclass(string: string) trait mytrait extends mycaseclass val myct = new mycaseclass("hi") mytrait
i guess boils down question, whether mytrait forced mixable instantiations of mycaseclass or whether mytrait inheriting class members (field values , methods) of mytrait , overwriting them. in first case okay inherit mycaseclass, in latter case not okay. 1 it?
to investigate, advanced experiment with
trait mytrait extends mycaseclass { def equals(m: mycaseclass): boolean = false def equals(m: mycaseclass mytrait): boolean = false } val myc = new mycaseclass("hi") myct.equals(myc) // res0: boolean = true
letting me believe equals of mycaseclass used, not 1 of mytrait. suggest okay trait extend case class (while not okay class extend case class).
however, not sure whether experiment legit. shed light on matter?
basically, trait can extend any class, it's better use them regular classes (oop-style).
anyway, equals contract still broken regardless of trick (note standard java's equals
defined on any
, used default let's in hashmap
or ==
):
scala> trait mytrait extends mycaseclass { | override def equals(m: any): boolean = false | } defined trait mytrait scala> val myct = new mycaseclass("hi") mytrait myct: mycaseclass mytrait = mycaseclass(hi) scala> val myc = new mycaseclass("hi") myc: mycaseclass = mycaseclass(hi) scala> myc.equals(myct) res4: boolean = true scala> myct.equals(myc) res5: boolean = false
besides, hashcode/equals
isn't reason...
extending case class
class unnatural because case class
represents adt models data - not behavior.
that's why should not add methods (in ood terms case class
es designed anemic approach). so, after eliminating methods - trait can mixed class becomes nonsense point of using traits case classes model disjunction (so traits interfaces here - not mix-ins):
//your data model (haskell-like): data color = red | blue //scala trait color case object red extends color case object blue extends color
if color
mixed blue
- it's same
data color = blue
even if require more complex data, like
//your data model (haskell-like): data color = bluelike | redlike data bluelike = blue | lightblue data redlike = red | pink //scala trait color extends red trait bluelike extends color trait redlike extends color case class red(name: string) extends redlike //is ok case class blue(name: string) extends bluelike //won't compile!!
binding color
red
doesn't seem approach (in general) won't able case object blue extends bluelike
p.s. case classes not intended used in oop-style (mix-ins part of oop) - interact better type-classes/pattern-matching. recommend move complex method-like logic away case class. 1 approach be:
trait mycaseclasslogic1 { def applylogic(cc: mycaseclass, param: string) = {} } trait mycaseclasslogic2 extends mycaseclasslogic { def applylogic2(cc: mycaseclass, param: string) = {} } object mycaseclasslogic extends mycaseclasslogic1 mycaseclasslogic2
you use self-type or trait extends
here can notice it's redundant applylogic
bound mycaseclass
:)
another approach implicit class
(or can try more advanced stuff type-classes)
implicit class mycaseclasslogic(o: mycaseclass) { def applylogic = {} }
p.s.2 anemic vs rich. adt
not precisely anemic model applies immutable (stateless) data. if read the article, martin fowler's approach oop/ood stateful default - that's assumes in of part of article implying service layer , business layer should have separate states. in fp (at least in practice) still separate domain logic service-logic, separate operations data (in every layer), matter.
Comments
Post a Comment