score:132
My preferred way of avoiding case class inheritance without code duplication is somewhat obvious: create a common (abstract) base class:
abstract class Person {
def name: String
def age: Int
// address and other properties
// methods (ideally only accessors since it is a case class)
}
case class Employer(val name: String, val age: Int, val taxno: Int)
extends Person
case class Employee(val name: String, val age: Int, val salary: Int)
extends Person
If you want to be more fine-grained, group the properties into individual traits:
trait Identifiable { def name: String }
trait Locatable { def address: String }
// trait Ages { def age: Int }
case class Employer(val name: String, val address: String, val taxno: Int)
extends Identifiable
with Locatable
case class Employee(val name: String, val address: String, val salary: Int)
extends Identifiable
with Locatable
score:8
In these situations I tend to use composition instead of inheritance i.e.
sealed trait IVehicle // tagging trait
case class Vehicle(color: String) extends IVehicle
case class Car(vehicle: Vehicle, doors: Int) extends IVehicle
val vehicle: IVehicle = ...
vehicle match {
case Car(Vehicle(color), doors) => println(s"$color car with $doors doors")
case Vehicle(color) => println(s"$color vehicle")
}
Obviously you can use a more sophisticated hierarchy and matches but hopefully this gives you an idea. The key is to take advantage of the nested extractors that case classes provide
score:14
case classes are perfect for value objects, i.e. objects that don't change any properties and can be compared with equals.
But implementing equals in the presence of inheritance is rather complicated. Consider a two classes:
class Point(x : Int, y : Int)
and
class ColoredPoint( x : Int, y : Int, c : Color) extends Point
So according to the definition the ColorPoint(1,4,red) should be equal to the Point(1,4) they are the same Point after all. So ColorPoint(1,4,blue) should also be equal to Point(1,4), right? But of course ColorPoint(1,4,red) should not equal ColorPoint(1,4,blue), because they have different colors. There you go, one basic property of the equality relation is broken.
update
You can use inheritance from traits solving lots of problems as described in another answer. An even more flexible alternative is often to use type classes. See What are type classes in Scala useful for? or http://www.youtube.com/watch?v=sVMES4RZF-8
score:45
Since this is an interesting topic to many, let me shed some light here.
You could go with the following approach:
// You can mark it as 'sealed'. Explained later.
sealed trait Person {
def name: String
}
case class Employee(
override val name: String,
salary: Int
) extends Person
case class Tourist(
override val name: String,
bored: Boolean
) extends Person
Yes, you have to duplicate the fields. If you don't, it simply would not be possible to implement correct equality among other problems.
However, you don't need to duplicate methods/functions.
If the duplication of a few properties is that much of an importance to you, then use regular classes, but remember that they don't fit FP well.
Alternatively, you could use composition instead of inheritance:
case class Employee(
person: Person,
salary: Int
)
// In code:
val employee = ...
println(employee.person.name)
Composition is a valid and a sound strategy that you should consider as well.
And in case you wonder what a sealed trait means — it is something that can be extended only in the same file. That is, the two case classes above have to be in the same file. This allows for exhaustive compiler checks:
val x = Employee(name = "Jack", salary = 50000)
x match {
case Employee(name) => println(s"I'm $name!")
}
Gives an error:
warning: match is not exhaustive!
missing combination Tourist
Which is really useful. Now you won't forget to deal with the other types of Person
s (people). This is essentially what the Option
class in Scala does.
If that does not matter to you, then you could make it non-sealed and throw the case classes into their own files. And perhaps go with composition.
Source: stackoverflow.com
Related Query
- Scala case class inheritance
- Replacing case class inheritance with extractors preserving exhaustiveness checks in Scala
- Is it possible to take advantage of case class inheritance in pattern matching in Scala 2.10.0?
- Scala nested case class self-bounding inheritance
- Scala case class inheritance with code reusability
- IntelliJ Scala Plugin's case class indentation is absurd
- How to update a mongo record using Rogue with MongoCaseClassField when case class contains a scala Enumeration
- Case class to map in Scala
- Extending scala case class without constantly duplicating constructors vals?
- How to convert Row of a Scala DataFrame into case class most efficiently?
- How to get around the Scala case class limit of 22 fields?
- Scala class and case class == comparison
- Scala case class private constructor but public apply method
- Scala case class extending Product with Serializable
- Scala case class update value
- Scala 2.10 reflection, how do I extract the field values from a case class, i.e. field list from case class
- Scala case class prohibits call-by-name parameters?
- Scala 2.10, its impact on JSON libraries and case class validation/creation
- Scala - No TypeTag Available Exception when using case class to try to get TypeTag?
- Python equivalent of Scala case class
- Read CSV in Scala into case class instances with error handling
- Read case class object from string in Scala (something like Haskell's "read" typeclass)
- If case class inheritance is prohibited, how to represent this?
- Can I get a Scala case class definition from an Avro schema definition?
- Using Jackson to (De)-serialize a Scala Case Class
- Why not make every Scala class a case class?
- Case to case inheritance in Scala
- scala - parse json of more than 22 elements into case class
- Update operations on a Scala Case Class
- Understanding Case class and Traits in Scala
More Query from same tag
- Variance of Scala List map function
- Show only one error message, on scala forms
- Spark filtering with regex
- Akka-Streams collecting data (Source -> Flow -> Flow (collect) -> Sink)
- How can I provide a scala companion object's class to Java?
- Play & JSON: How to transform a sequence of (String, JsValue) into a JsObject
- Support Jackson @JsonFilter async DeferredResult
- Spring MVC - send model to view and back to controller
- How to define Scala package object?
- Scala elegant way to convert a multiple optional objects to a different object if at least one of the objects defined
- Cannot construct a Read instance for type User. Type misunderstanding with Doobie in Scala
- Map the types of a shapeless HList
- How can I access values in a scala.collection.mutable.WrappedArray of WrappedArray's in java
- How to read date, time and Timestamp from hbase column
- How to access and update a value in a mutable map of map of maps
- PlayFramework 2.0 Json to List[String] Conversion
- How to catch RejectedExecutionException when using Scala futures?
- Why would sbt reload gen-idea use 6GB of memory?
- How to get sbt to stop trying to pull latest transitive range dependency on each build
- Scala by Example - problems with currying
- Spark refuse to zip RDD
- How to change an array of integers to individual columns in Spark (scala)?
- What to set as default when the type is A (Scala)
- ZipFileSystem can't open OutputStream with a slash in the path
- Print gatling session map values on console
- Get last inserted ID from MongoDB using Play Scala
- Grouping test cases or "shared_examples_for" equivalent in specs2
- Pick out the Nth element of a HList of Lists and return that value as a HList of values
- Creating a TestActorRef results in NullPointerException
- Issuing native system commands in Scala