Scala best practice on using self in method - scala

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

Related

How to return the concrete Product type from my function?

I have different product types like:
sealed trait Product
case class Downloadable(url: String) extends Product
case class Shippable(weight: Int) extends Product
case class Virtual(name: String) extends Product
object Load {
def get(id: Int): Product = id match {
case 1 => Downloadable("google.com")
case 2 => Shippable(100)
case _ => Virtual("virtuallll")
}
}
println(Load.get(1))
println(Load.get(2))
println(Load.get(3))
val d = Load.get(1)
println(d.url) // error value url is not a member
I don't have access to the properties of the concrete type, is it possible to be able to?
Pattern matching.
Load.get(1) match {
case dl:Downloadable => println(s"URL: ${dl.url}")
case shp:Shippable => println(s"weight: ${shp.weight}")
case vt:Virtual => println(s"name: ${vt.name}")
}
Each variable (dl, shp, vt) exists only within its case code block.
You are trying to deal uniformly with instances that are not uniform. The solution is to make them uniform, that's what base classes and traits are for: defining and describing common interface.
sealed trait Product[T] { def data: T }
case class Downloadable(url: String) extends Product[String] { def data = url }
case class Shippable(weight: Int) extends Product[Int] { def data = weight }
case class Virtual(name: String) extends Product[String] { def data = name }
then you can do println(Product.get(1).data)
Alternatively (and I don't really recommend that, but if it is like the only place in the codebase where you need this, implementing it properly is too complicated) you can exploit the fact that case classes are instances of Product (not your Product, but scala library trait representing a cartesian product).
All Product instances have a method productIterator that lets you iterate through values of all member variables. So, you can just do this with your existing definitions:
println(Product.load(1).productIterator.next)

Extend case class from another case class

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

How to make my handle method polymorphic when using traits

I want my handle method to be able to take any Animal type and then be able to actually have the specific type so I can continue processing.
I just sketched out what I am looking for:
sealed trait Animal
case class Dog(id: Int) extends Animal
case class Cat(id: Int) extends Animal
case class Owl(id: Int) extends Animal
object AnimalHandler {
def handle(animal: Animal) = animal match {
case Dog => processDog(dog)
case Cat => processCat(cat)
}
}
How can I design my domain to work like the above?
The code you have pretty much works as-is.
The syntax on the pattern match would need to include a variable name, and if you're actually using the attributes of the case classes you would probably use the pattern to extract them.
sealed trait Animal
case class Dog(id: Int) extends Animal
case class Cat(id: Int) extends Animal
case class Owl(id: Int) extends Animal
def processDog(dog: Dog) = println(s"woof ${dog.id}")
def processCat(id: Int) = println(s"meow $id")
def processOwl(owl: Owl, id: Int) = println(s"hoot ${owl.id}")
object AnimalHandler {
def handle(animal: Animal) = {
case dog: Dog => processDog(dog)
case Cat(id) => processCat(id)
case owl # Owl(id) => processOwl(owl, id)
}
}
Some notes:
given a sealed trait, the compiler will warn you if your pattern match isn't complete (in your case you were missing handling for Owl).
if the body of a method/function is nothing but a pattern match on the argument you can skip the animal match

Scala - Abstract types and Implicit Parameter Resolution

I'm using Scala 2.10.4.
Please bare with the analogy - the actual code is deeply embedded in a complicated program, so rather than explain that, I’ll abstract the problem in a time honoured way to talk about Animals ;-)
In scala I have 2 traits - for example:
Animal, and HouseBase.
I have no access to change Animal, but I inherit from it with classes like Dog, Rabbit, Fish. Annoyingly I can’t change every subclass as I don’t own all the subclasses I use.
My animals all live somewhere - their homes must inherit from HouseBase. I can change HouseBase and it’s subclasses (via another layer of abstraction, if I must).
So a Dog is a subclass of Animal, and would live in a Kennel which is a subclass of HouseBase.
A Rabbit would live in a Hutch, and a Fish in a Tank.
Note there is not a 1:1 relationship enforced here - a Fish could also live in a Pond, and we’d have to be able to handle that too.
What I’d hoped was that -- given a concrete animal (eg Fish), that is referenced via an abstract type Animal, and given a concrete return type (eg Tank), Scala would be able to automagically pick the correct implicit parameter in the design I have below.
object AnimalSelectionProblem extends App {
def abstractFish : Animal = new Fish(true, 20.0)
def concreteFish : Fish = new Fish(false, 30.0)
def abstractDog : Animal = new Dog("tasty bone")
def concreteDog : Dog = new Dog("yummy bone")
def abstractRabbit : Animal = new Rabbit(5)
def concreteRabbit : Rabbit = new Rabbit(10)
import HouseImplicits._
val myTank1: Tank = HouseImplicits.create(abstractFish)
val myTank2: Tank = HouseImplicits.create(concreteFish)
val myKennel1: Kennel = HouseImplicits.create(abstractDog)
val myKennel2: Kennel = HouseImplicits.create(concreteDog) // This works
val myhutch1: Hutch = HouseImplicits.create(abstractRabbit)
val myhutch2: Hutch = HouseImplicits.create(concreteRabbit) // This works
}
However there are 2 related problems.
Problem 1 - If the animal is referenced as an abstract, then the implicit parameter will only look for functions that take the abstract type (Animal) rather than the underlying concrete type. I suspect the solution may be to use ClassTags, because Scala doesn’t seem to use runtime time information? I had a go at implementing this and got hopelessly l lost (I’m fairly new to Scala!).
Problem 2 - If my animal can live in more than one type of House then a similar issue occurs, that even if a concrete return type is specified, the compiler will find the 2 implicit objects for Fish ambiguous. I’m a bit stumped about what to do here!
I can dream up solutions with manual boilerplate to match the type at runtime, but this isn’t very extensible.
Any ideas gratefully received! Rest of the code is below.
Edit - these links seems to confirm what I had suspected. That compile time polymorphism is used and hence the runtime type cannot be known:
http://like-a-boss.net/2013/03/29/polymorphism-and-typeclasses-in-scala.html
https://softwareengineering.stackexchange.com/questions/258698/is-it-possible-to-have-ad-hoc-polymorphism-with-runtime-dispatch
So, I guess my question now is, given this, is there a way to modify my example to use runtime dispatch?
Animals:
trait Animal {
}
class Dog(val boneName: String) extends Animal
class Rabbit(val length: Int) extends Animal
class Fish(val likesFrogs: Boolean, val optimumTemp: Double) extends Animal
Houses and Implicits:
sealed trait HouseBase
// Made up some arbitrary member variables
case class Kennel(posessions: Seq[String]) extends HouseBase
case class Hutch(length: Int) extends HouseBase
case class Tank(waterTemp: Double) extends HouseBase
case class Pond(containsFrog: Boolean) extends HouseBase
sealed trait HouseCreator[A <: Animal, HB <: HouseBase] {
def create(animal: A): HB
}
object HouseImplicits {
implicit object BuildKennelForDog extends HouseCreator[Dog, Kennel] {
override def create(dog: Dog): Kennel = {
new Kennel(Seq(dog.boneName))
}
}
implicit object BuildTankForFish extends HouseCreator[Fish, Tank] {
override def create(fish: Fish): Tank = {
new Tank(fish.optimumTemp)
}
}
implicit object BuildPondForFish extends HouseCreator[Fish, Pond] {
override def create(fish: Fish): Pond = {
new Pond(fish.likesFrogs)
}
}
implicit object BuildHutchForRabbit extends HouseCreator[Rabbit, Hutch] {
override def create(rabbit: Rabbit): Hutch = {
new Hutch(rabbit.length*5)
}
}
def create[A <: Animal, H <: HouseBase](animal: A)(implicit house: HouseCreator[A,H]) : H = {
val newHouse = house.create(animal)
newHouse
}
}
So basically you want the following design:
At compile time the concrete type of HouseBase is known.
At compile time the concrete type of Animal is not known.
Create a specific type HouseBase for Animal provided runtime animal data.
Can't change Animal implementations, and don't really want to change HouseBase implementations.
The desirable thing is of course to have the concrete types of Animals available at compile time. Since there seems to be some knowledge of that (you know which HouseBase to create for an animal variable at compile time), you may try to use type-safe cast from shapeless to get an Option of a concrete Animal type.
But if it's not possible you have to use run-time dispatch of animals.
In that case I think the method create should have the following signature:
def create[HB <: HouseBase](animal: Animal): Option[HB]
You know the concrete type of the HouseBase so you may as well pass it as type parameter, and the return value is Option to account for a possible mismatch between the type of the provided animal and suitable animal types for a concrete HouseBase
One possible way to implement that is the following code with a single object that has all the knowledge about the production of HouseBases from Animals (it should be also possible to achieve the same thing by moving the creation code into companion objects of concrete HouseBases):
sealed trait HouseCreator[HB <: HouseBase] {
def create(animal: Animal): Option[HB]
}
object HouseCreator {
implicit object KennelCreator extends HouseCreator[Kennel] {
def create(animal: Animal): Option[Kennel] = animal match {
case dog: Dog => Some(Kennel(Seq(dog.boneName)))
case _ => None
}
}
implicit object HutchCreator extends HouseCreator[Hutch] {
def create(animal: Animal): Option[Hutch] = animal match {
case rabbit: Rabbit => Some(Hutch(rabbit.length * 5))
case _ => None
}
}
implicit object TankCreator extends HouseCreator[Tank] {
def create(animal: Animal): Option[Tank] = animal match {
case fish: Fish => Some(Tank(fish.optimumTemp))
case _ => None
}
}
implicit object PondCreator extends HouseCreator[Pond] {
def create(animal: Animal): Option[Pond] = animal match {
case fish: Fish => Some(Pond(fish.likesFrogs))
case _ => None
}
}
def create[HB <: HouseBase : HouseCreator](animal: Animal): Option[HB] =
implicitly[HouseCreator[HB]].create(animal)
}
Then you can call the functions this way:
val myTank1: Option[Tank] = HouseCreator.create[Tank](abstractFish)
val myTank2: Option[Tank] = HouseCreator.create[Tank](concreteFish)
// Types of the variables can also be inferred automatically
val myKennel1 = HouseCreator.create[Kennel](abstractDog)
val myKennel2 = HouseCreator.create[Kennel](concreteDog)
val myhutch1 = HouseCreator.create[Hutch](abstractRabbit)
val myhutch2 = HouseCreator.create[Hutch](concreteRabbit)
Also, the boilerplate code in HouseCreator can be reduced by using PartialFunctions:
sealed trait HouseCreator[HB <: HouseBase] {
def create: PartialFunction[Animal, HB]
}
object HouseCreator {
implicit object KennelCreator extends HouseCreator[Kennel] {
def create = {
case dog: Dog => Kennel(Seq(dog.boneName))
}
}
implicit object HutchCreator extends HouseCreator[Hutch] {
def create = {
case rabbit: Rabbit => Hutch(rabbit.length * 5)
}
}
implicit object TankCreator extends HouseCreator[Tank] {
def create = {
case fish: Fish => Tank(fish.optimumTemp)
}
}
implicit object PondCreator extends HouseCreator[Pond] {
def create = {
case fish: Fish => Pond(fish.likesFrogs)
}
}
def create[HB <: HouseBase : HouseCreator](animal: Animal): Option[HB] =
implicitly[HouseCreator[HB]].create.lift(animal)
}
What you want is for the compiler to deduce the run-time type of your subclass when it is declared statically as an instance of its superclass. This is provably impossible, so don't try to make it work unless you're hoping to win some kind of computer science award!
Instead of parameterizing your HouseCreator class, you could write it to have a single create() method that accepts an object of type Animal. It could create the appropriate House using a case match that matches based on the run-time subtype of Animal.
sealed trait HouseCreator {
def create(animal: Animal): HouseBase {
animal match {
case dog: Dog => new Kennel(Seq(dog.boneName))
case fish: Fish => // etc...
}
}
}
This would only be able to return a HouseBase object rather than a specific subclass (at least as I implemented it here). You could always case match the return value as well.

scala Class.forName pattern matching

I am newbie using scala .
I am trying to use pattern matching with reflection:
abstract class Person{
val name:String,
val age:Int
}
case class Man (name:String,age:Int,workPlace:String) extends Person
val aclass = Class.forName("man")
aclass match{
case m:Man => println("this is a man class")
case p:Person => println("Person")
case _ => println("Nothing")
}
I am always getting to default part ("Nothing") and to the correct match (Man) . what am I doing wrong ?
Thanks
First, you need to use the full and properly cased class name. Second, Class.forName returns a Class[_], not an instance of the class you give it. Take a look at modifications to your code that I made to get a clearer picture:
abstract class Person {
val name: String //removed comma
val age: Int
}
case class Man(name: String, age: Int, workPlace: String) extends Person
val manClassName = classOf[Man].getName //get the proper name of the class
println("Man class name: %s".format(manClassName))
val aclass = Class.forName(manClassName) //returns Class[Man]
aclass match {
case m: Class[Man] => println("this is a man class") //Pattern match on Class[Man]
case p: Class[Person] => println("Person")
case _ => println("Nothing")
}
Few problems with your code. Maybe I'm not understanding what you're doing with Class.forName(String) so I changed things a bit.
First, use case classes for these so you get your getters and setters for encapsulation.
sealed trait Person
case class Man (name:String,age:Int,workPlace:String) extends Person
Next, Class.forName returns a Class, not an object.
So you need to instantiate by calling the Constructor of Man
val man = Man("Jo", 24, "anywhere")
Then you can pattern match on that:
man match{
case m:Man => println("this is a man class")
case p:Person => println("Person")
case _ => println("Nothing")
}
It will match the first case that hits though so make sure you order man and person cases how you want them.
For reflection, you'll want to look at TypeTags and ClassTags
http://docs.scala-lang.org/overviews/reflection/typetags-manifests.html