I have two case class Person and Employee
case class Person(identifier: String) {}
case class Employee (salary: Long) extends Person {}
I am getting following error:
Unspecified value parameters: identifier: String
Error: case class Employee has case ancestor Person, but case-to-case inheritance is prohibited. To overcome this limitation, use extractors to pattern match on non-leaf nodes
I am new to Scala and not able to understand what I have to do.
Version:
Scala : 2.11
Unfortunately, I'm afraid it is not possible for case class to extend another case class.
The inheritance in "plain" classes would look like:
class Person(val identifier: String) {}
class Employee(override val identifier: String, salary: Long)
extends Person(identifier) {}
val el = new Employee("abc-test", 999)
println(el.identifier) // => "abc-test"
If you would like to achieve a similar effect with case classes, you would need to reach out to traits:
trait Identifiable {
def identifier: String
}
case class Person(identifier: String) extends Identifiable {}
case class Employee(identifier: String, salary: Long)
extends Identifiable {}
val el = Employee("abc-test", 999)
println(el.identifier) // => "abc-test"
Defining extractors
Extractor provides a way for defining a matching statement used in pattern matching. It is defined in an object in unaply method.
Let's consider the first example again adding support for extractors:
class Person(val identifier: String)
class Employee(override val identifier: String, val salary: Long)
extends Person(identifier)
object Person {
def unapply(identifier: String): Option[Person] = {
if (identifier.startsWith("PER-")) {
Some(new Person(identifier))
}
else {
None
}
}
}
object Employee {
def unapply(identifier: String): Option[Employee] = {
if (identifier.startsWith("EMP-")) {
Some(new Employee(identifier, 999))
}
else {
None
}
}
}
Now, let's define a method that will define pattern matching using those extractors:
def process(anInput: String): Unit = {
anInput match {
case Employee(anEmployee) => println(s"Employee identified ${anEmployee.identifier}, $$${anEmployee.salary}")
case Person(aPerson) => println(s"Person identified ${aPerson.identifier}")
case _ => println("Was unable to identify anyone...")
}
}
process("PER-123-test") // => Person identified PER-123-test
process("EMP-321-test") // => Employee identified EMP-321-test, $999
process("Foo-Bar-Test") // => Was unable to identify anyone...
Case classes in Scala add several different features but often you really use only some of them. So the main question you need to answer is which features you really need. Here is a list based on the spec:
remove the need to type val before field names/constructor params
remove the need for new by adding apply method to the companion object
support for pattern matching by adding unapply method to the companion object. (One of nice things of Scala is that pattern-matching is done in a non-magical way, you can implement it for any data type without requiring it to be a case class)
add equals and hashCode implementations based on all the fields
add toString implementations
add copy method (useful because case classes are immutable by default)
implement Product trait
A reasonable guess of the equivalent for case class Person(identifier: String) is
class Person(val identifier: String) extends Product {
def canEqual(other: Any): Boolean = other.isInstanceOf[Person]
override def equals(other: Any): Boolean = other match {
case that: Person => (that canEqual this) && identifier == that.identifier
case _ => false
}
override def hashCode(): Int = identifier.hashCode
override def toString = s"Person($identifier)"
def copy(newIdentifier: String): Person = new Person(newIdentifier)
override def productElement(n: Int): Any = n match {
case 0 => identifier
case _ => throw new IndexOutOfBoundsException(s"Index $n is out of range")
}
override def productArity: Int = 1
}
object Person {
def apply(identifier: String): Person = new Person(identifier)
def unapply(person: Person): Option[String] = if (person eq null) None else Some(person.identifier)
}
case class Employee(override val identifier: String, salary: Long) extends Person(identifier) {}
Actually the main objections to inheriting from a case class and especially making a case class inheriting another one are the Product trait, copy and equals/hashCode because they introduce ambiguity. Adding canEqual partially mitigates the last problem but not the first ones. On the other hand in a hierarchy like yours, you probably don't need the copy method or Product implementation at all. If you don't use Person in pattern matching, you don't need unapply as well. Most probably all you really need case for is apply, toString and hashCode/equals/canEqual.
Inheriting from case classes (even with regular non-case classes, which is not prohibited) is a bad idea. Check this answer out to get an idea why.
You Person does not need to be a case class. It actually does not need to be a class at all:
trait Person {
def identifier: String
}
case class Employee(identifier: String, salary: Long) extends Person
Related
HI I have a case when calling a method to use self. Now not sure the best practice to do this in Scala. I have created a example of how I'm doing it just wanted to ask is this the best way of doing so.
sealed trait Animal {
// match on self
final def speak(): Unit = {
this match {
case Cat(name) => println("spoken like a Cat named: " + name)
case Dog(name) => println("spoken like a Dog named: " + name)
case Pig(name) => println("spoken like a Pig named: " + name)
}
}
final def whoAmI(): Unit = {
this match {
case Cat(_) => println("I am a Cat")
case Dog(_) => println("I am a Dog")
case Pig(_) => println("Could be a Pig")
}
}
}
final case class Cat(name: String) extends Animal
final case class Dog(name: String) extends Animal
final case class Pig(name: String) extends Animal
If your requirement is only to know which sub-type is used, it can be accessed in a more straightforward manner with just this.getClass():
sealed trait Animal {
val name: String
final def speak(): Unit =
println(s"spoken like a ${this.getClass.getSimpleName} named: ${name}")
final def whoAmI(): Unit =
println(s"I am a ${this.getClass.getSimpleName}")
}
If all the implementing sub-types are characterized by a name, that would be convenient to declare an abstract val name: String, which will allow to access the field in speak().
For a use case like this the matchers are not the best option: for each implementing sub-type you have to add an entry in the matchers (may become difficult to maintain). I'd suggest using inheritance: if you have a behavior differentiated among the sub-types, declare an abstract method in the trait, call it from it, but its implementations should remain at sub-types level.
Yes, your use of pattern matching on this is correct.
Since your hierarchy is sealed, you know, that there will not be any new types to account for - otherwise you should have the _ => ... clause.
You can express your second case a bit simpler, since you dont care about the parameters, only about the type.
final def whoAmI(): Unit = {
this match {
case _:Cat => println("I am a Cat")
case _:Dog => println("I am a Dog")
case _:Pig => println("Could be a Pig")
}
}
Finally, this always refers to the innermost type. In case of nested inner classes, you might want to use an alias, like self:
trait Tweeter {
this: self => // reassign this into self, so it can be accessed from an inner class
We use the cake pattern to abstract Components (DB, Mock) with self-type annotation, that are Injected at the top level call.
In one case class we want to be able to enrich it's behavior by extending common trait. But how to do it if we want this case class to call an abstract component?
Refactoring the case class as abstract will remove all the implementation of apply, unapply, copy ... Things that we need to do the mapping between database and model (for example using Slick).
Here is an exemple representing Plants into some Blocks as Resources owned by an Account:
trait Resource {
def getAccount: Future[Account]
}
case class Account(id: Int)
case class Block(id: Int, name:String, accountId: Int) extends Resource
case class Plant(id: Int, name: String, blockId: Int) extends Resource {
this: PlantDBComponent =>
override def getAccount: Future[Account] = plantDB.getAccount(this)
}
trait PlantDBComponent {
def plantDB: PlantDB
trait PlantDB {
def getAccount(plant: Plant): Future[Account]
}
}
trait SlickPlantDBComponent {
def blockDB = SlickPlantDB()
trait SlickPlantDB extends PlantDB {
def getAccount(block: Block): Future[Account] = {
val q = for {
block <- BlockTable if block.id === plant.blockId
account <- AccountTable if account.id === block.accountId
} yield account
db.run(q.result.head)
}
}
}
Any idea on how to do it without reimplementing all the case class boilerplate? Adding getAccount in a Resource companion object with case class pattern matching will not solve the problem
We choose to implement a ResourceService that, according to resource Type, return the Account the resource belong to.
Here is the trait component:
trait ResourceServiceComponent {
val resourceService: ResourceService
trait ResourceService {
def getAccount(resource: Resource): Future[Account] = {
resource match {
case plant: Plant => blockDB.getAccount(plant.blockId)
case ...
}
}
}
}
I have an abstract base class, Foo, whose constructor I'd like to have an optional parameter. If none is provided, I'll just give it a None value.
A source Foo will not have parents, so I'd just like to construct them without a list of parents (leave default value for parent list)
A derived Foo might have provided parents, so I'd like to mimic the signature of the Foo base class.
Below is my attempt:
abstract class Foo(val id: String, var parentIds: Option[List[String]]=None) { }
case class SourceFoo(override val id: String)
extends Foo(id, parentIds=None) { }
case class DerivedFoo(override val id: String,
override var parentIds: Option[List[String]])
extends Foo(id, parentIds) { }
I'm getting a compiler error that a mutable variable cannot be overridden (referencing the parentIds in the DerivedFoo constructor.
This list is subject to change, so I don't want to make it a val (which removes my compiler issues).
This is a very basic OO issue, so it must be simpler than I seem to be making it. How can I achieve my desired behavior idiomatically?
I managed to fix this after reading the documentation:
The constructor parameters of case classes are treated as public values and can be accessed directly.
Since my base class is abstract, I can simply extend it with default, val construction.
I simply need to specify that parentIds is a var in the DerivedFoo constructor.
abstract class Foo(id: String, parentIds: Option[List[String]]=None) { }
case class SourceFoo(id: String) extends Foo(id) { }
case class DerivedFoo(id: String, var parentIds: Option[List[String]]=None)
extends Foo(id, parentIds) { }
Here is another probably better way to go about it. Explictly acknowledge the difference between class parameters and class members. You also can make them private members if you like following this block of code.
abstract class Foo(identifier: String, parentIdentifiers: Option[List[String]]) {
val id = identifier
var parentIds = parentIdentifiers
}
case class SourceFoo(override val id: String) extends Foo(id, parentIdentifiers = None) { }
case class DerivedFoo(identifier: String, parentIdentifiers: Option[List[String]]) extends Foo(identifier, parentIdentifiers) { }
After that, you can create DerivedFoo and refer to the members as you are probably expecting, and you won't have two members with different names.
REPL output:
scala> DerivedFoo("1", Some(List("200","201","202")))
res0: DerivedFoo = DerivedFoo(1,Some(List(200, 201, 202)))
scala> res0.parentIds
res1: Option[List[String]] = Some(List(200, 201, 202))
scala> res0.parentIds = Some(List("800", "801", "802"))
res0.parentIds: Option[List[String]] = Some(List(800, 801, 802))
I think you can achieve your goal by changing the name of the parameter in the abstract class as follows.
abstract class Foo(val id: String, var parentIdentifiers: Option[List[String]]) {
parentIdentifiers = None
}
case class SourceFoo(override val id: String)
extends Foo(id, parentIdentifiers = None) { }
case class DerivedFoo(override val id: String,
var parentIds: Option[List[String]])
extends Foo(id, parentIds) { }
For the mutation, you can import scala.collection.mutable and use mutable.ListBuffer instead of List.
I assume of course, that you won't change the parentIds of a DerivedFoo instance from Some to None.
This will allow you use vals but still have mutable state.
But I wouldn't say mutable state is idiomatic Scala.
You usually use immutable val and List, and just copy the object whenever you want to change the list.
val fooA = SourceFoo("a")
val fooB = DerivedFoo("b", "a" :: Nil)
val fooB2 = fooB.copy(parentIds = fooB.parentIds :+ "x")
So to be more idiomatic, the simplest you can do is
sealed abstract class Foo(val id: String, val parentIdsOpt: Option[List[String]])
case class SourceFoo(override val id: String)
extends Foo(id, None)
case class DerivedFoo(override val id: String, val parentIds: List[String])
extends Foo(id, Some(parentIds))
Which is pretty close to what you had.
Note that DerivedFoo.parentIds isn't Option anymore, because DerivedFoo always has parents, so you don't have to deal with Option. (You still have to deal with empty list, though)
Also note the sealed keyword on the trait, which is not required, but recommended if you want to match on an instance of the abstract class or trait. (You can use sealed only if you own all the sub-classes, which seems to be the case in your example)
I am still pretty new to Scala and looking at using Slick.
I also am looking at Accord (github.com/wix/accord) for validation.
Accord's validation seems to be on objects as a whole, but I want to be able to define validators for field types, so I've thought of using type aliasing using value classes so that I can easily re-use validations across various case classes that use those field types.
So, I've defined the following:
object FieldTypes {
implicit class ID(val i: Int) extends AnyVal
implicit class UserPassword(val s: String) extends AnyVal
implicit class Email(val s: String) extends AnyVal
implicit class Name(val s: String) extends AnyVal
implicit class OrgName(val s: String) extends AnyVal
implicit class OrgAlias(val s: String) extends AnyVal
}
package object validators {
implicit val passwordValidator = validator[UserPassword] { _.length is between(8,255) }
implicit val emailValidator = validator[Email] { _ is notEmpty }
implicit val nameValidator = validator[Name] { _ is notEmpty }
implicit val orgNameValidator = validator[OrgName] { _ is notEmpty }
implicit val teamNameValidator = validator[TeamName] { _ is notEmpty }
}
case object Records {
import FieldTypes._
case class OrganizationRecord(id: ID, uuid: UUID, name: OrgName, alias: OrgAlias)
case class UserRecord(id: ID, uuid: UUID, email: Email, password: UserPassword, name: Name)
case class UserToOrganizationRecord(userId: ID, organizationId: ID)
}
class Tables(implicit val p: JdbcProfile) {
import FieldTypes._
import p.api._
implicit object JodaMapping extends GenericJodaSupport(p)
case class LiftedOrganizationRecord(id: Rep[ID], uuid: Rep[UUID], name: Rep[OrgName], alias: Rep[OrgAlias])
implicit object OrganizationRecordShape extends CaseClassShape(LiftedOrganizationRecord.tupled, OrganizationRecord.tupled)
class Organizations(tag: Tag) extends Table[OrganizationRecord](tag, "organizations") {
def id = column[ID]("id", O.PrimaryKey)
def uuid = column[UUID]("uuid", O.Length(36, varying=false))
def name = column[OrgName]("name", O.Length(32, varying=true))
def alias = column[OrgAlias]("alias", O.Length(32, varying=true))
def * = LiftedOrganizationRecord(id, uuid, name, alias)
}
val organizations = TableQuery[Organizations]
}
Unfortunately, I clearly misunderstand or overestimate the power of Scala's implicit conversions. My passwordValidator doesn't seem to recognize that there is a length property to UserPassword and my * declaration on my Organizations table doesn't seem to think that it complies to the shape defined in LiftedOrganizationRecord.
Am I just doing something really dumb here on the whole? Should I not be even trying to use these kinds of custom types and simply use standard types instead, defining my validators in a better way? Or is this an okay way of doing things, but I've just forgotten something simple?
Any advice would be really appreciated!
Thanks to some helpful people on the scala gitter channel, I realized that the core mistake was a misunderstanding of the conversion direction for value classes. I had understood it to be ValueClass -> WrappedValueType, but it's actually WrappedValueType -> ValueClass. Thus, Slick wasn't seeing, as an exmaple, ID as an Int.
I have two case classes, let's call them case class User & case class Ticket. Both of these case classes implement the operations required to be members of a the same TypeClass, in this case Argonaut's EncodeJson.
Is it possible to view these two separate types as the same without creating an empty marker type that they both extend?
trait Marker
case class User extends Marker
case class Ticket extends Marker
To make this concrete,we have two separate functions that return these case classes:
case class GetUser(userId: Long) extends Service[Doesn't Matter, User] {
def apply(req: Doesn't Matter): Future[User] = {
magical and awesome business logic
return Future[User]
}
}
case class GetTicket(ticketId: Long) extends Service[Doesn't Matter, Ticket] {
def apply(req: Doesn't Matter): Future[Ticket] = {
magical and awesome business logic
return Future[Ticket]
}
}
I would like to compose these two Services so that they return the same type, in this case argonaut.Json, but the compiler's response to an implicit conversions is "LOLNO"
implicit def anyToJson[A](a: A)(implicit e: EncodeJson[A]): Json = e(a)
Any ideas? Thanks!
If you've got these case classes:
case class User(id: Long, name: String)
case class Ticket(id: Long)
And these instances:
import argonaut._, Argonaut._
implicit val encodeUser: EncodeJson[User] =
jencode2L((u: User) => (u.id, u.name))("id", "name")
implicit val encodeTicket: EncodeJson[Ticket] = jencode1L((_: Ticket).id)("id")
And the following services (I'm using Finagle's representation):
import com.twitter.finagle.Service
import com.twitter.util.Future
case class GetUser(id: Long) extends Service[String, User] {
def apply(req: String): Future[User] = Future(User(id, req))
}
case class GetTicket(id: Long) extends Service[String, Ticket] {
def apply(req: String): Future[Ticket] = Future(Ticket(id))
}
(These are nonsense but that doesn't really matter.)
Then instead of using an implicit conversion to change the return type, you can write a method to transform a service like this:
def toJsonService[I, O: EncodeJson](s: Service[I, O]): Service[I, Json] =
new Service[I, Json] {
def apply(req: I) = s(req).map(_.asJson)
}
And then apply this to your other services:
scala> toJsonService(GetTicket(100))
res7: com.twitter.finagle.Service[String,argonaut.Json] = <function1>
You could also provide this functionality as a service or a filter, or if you don't mind getting a function back, you could just use GetTicket(100).andThen(_.map(_.asJson)) directly.
The key idea is that introducing implicit conversions should be an absolute last resort, and instead you should use the type class instance directly.