scala Class.forName pattern matching - scala

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

Related

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

Scala best practice on using self in method

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

Scala - union types in pattern matching

I have a trait like this:
trait Identifiable {
def id: Option[Long]
}
and then there are some other case classes which extend the Identifiable trait.
for example:
case class EntityA(id: Option[Long], name: String, created: Date) extends Identifiable
case class EntityB(id: Option[Long], price: Long, count: Int) extends Identifiable
assume that I have a Seq[Identifiable] and I want to assign new id to each one.
the simplest approach seems to be:
val xs: Seq[Identifiable] = ...
xs.map {
case x: EntityA => x.copy(id = Some(nextId))
case x: EntityB => x.copy(id = Some(nextId))
}
good! but there's is a problem.
The more subclasses, The more (duplicate) code to be written.
I tried to get help from Union Types:
xs.map {
case x: EntityA with EntityB => x.copy(id = Some(nextId))
}
or
xs.map {
case x # (_: EntityA | _: EntityB) => x.copy(id = Some(nextId))
}
but I got an error that says: Cannot resolve symbol copy
Any help would be appreciated.
Thanks.
Basically, what we want to do here is abstract over the actual type. The problem with that is copy is only implemented OOTB in terms of case classes, and Identifiable is a trait, so there may or may not be a copy method available at compile time, hence why the compiler is yelling at you.
Heavily inspired by this answer, I modified the provided example which uses Shapeless lenses:
import shapeless._
abstract class Identifiable[T](implicit l: MkFieldLens.Aux[T, Witness.`'id`.T, Option[Long]]){
self: T =>
final private val idLens = lens[T] >> 'id
def id: Option[Long]
def modifyId(): T = idLens.modify(self)(_ => Some(Random.nextLong()))
}
case class EntityA(id: Option[Long], name: String, create: Date) extends Identifiable[EntityA]
case class EntityB(id: Option[Long], price: Long, count: Int) extends Identifiable[EntityB]
And now, we can modify each id on any type extending Identifable[T] for free:
val xs: Seq[Identifiable[_]] = Seq(EntityA(Some(1), "", new Date(2017, 1, 1)), EntityB(Some(2L), 100L, 1))
val res = xs.map(_.modifyId())
res.foreach(println)
Yields:
EntityA(Some(-2485820339267038236),,Thu Feb 01 00:00:00 IST 3917)
EntityB(Some(2288888070116166731),100,1)
There is a great explanation regarding the individual parts assembling this answer in the provided link above by #Kolmar, so first and foremost go read the details of how lensing works for the other answer (which is very similar), and then come back to this for a reference of a minimal working example.
Also see #Jasper-M answer here for more ways of accomplishing the same.
Union types aren't the right path here. Consider:
xs.map {
case x # (_: EntityA | _: EntityB) => x.copy(id = Some(nextId))
}
When you say EntityA | EntityB Scala will try and find the supertype that holds these two types together. In this case that is Identifiable, which does not have the copy method and therefore the compiler can't resolve it.
Next:
xs.map {
case x: EntityA with EntityB => x.copy(id = Some(nextId))
}
When you say EntityA with EntityB you're saying "x is a type that is both an EntityA and EntityB at the same time". No such type exists and certainly not one that has a copy method on it.
Unfortunately, I don't think you can generically abstract over the copy method the way you're looking to do in plain Scala. I think your best bet is to add a copy method to your trait and implement methods in each of your sub-classes like so, which unfortunately means some boilerplate:
trait Identifiable {
def id: Option[Long]
def copyWithNewId(newId: Option[Long]): Identifiable
}
case class EntityA(id: Option[Long], name: String) extends Identifiable {
override def copyWithNewId(newId: Option[Long]) = this.copy(id = newId)
}
case class EntityB(id: Option[Long], count: Int) extends Identifiable {
override def copyWithNewId(newId: Option[Long]) = this.copy(id = newId)
}
This is more or less with your working pattern matching, except moving the copy call into the entities themselves.
Now this only applies to plain Scala. You can used more advanced libraries, such as Shapeless or Monocle to do this. See this answer which is pretty similar to what you're trying to do:
Case to case inheritence in Scala

Understanding breakdown of case classes

If I have case class defined as below
case class Calculator(brand: String, model: String)
How does it's companion object's unapply method would look like? What type of arguments would it take?
I am not able to emulate this by defining a class and then it's companion object by myself.
class abc (age:Int, name:String) {
}
object abc {
def apply(age:Int, name:String) = new abc(age, name)
def unapply(obj:abc) = Some("test")
}
abc(1, "aaaa")
res6: abc = abc#269f4bad
res6 match {
| case abc(1, "aaaa") => println("found")
| }
error: too many patterns for object abc offering String: expected 1, found 2
case abc(1, "aaaa") => println("found")
^
<console>:14: error: type mismatch;
found : Int(1)
required: String
case abc(1, "aaaa") => println("found")
You'll need to make age and name members of your class so that they are accessible after construction (can be done by making them vals), and then use them in unapply:
class abc (val age:Int, val name:String)
object abc {
def apply(age:Int, name:String) = new abc(age, name)
def unapply(candidate: abc) = Some((candidate.age, candidate.name))
}
Which would match correctly:
scala> new abc(2, "bbbb") match {
| case abc(1, "aaaa") => println("found 1")
| case abc(2, "bbbb") => println("found 2")
| case _ => println("not found")
| }
found 2
Tzach beat me to it..
Your error message btw. is because of the mismatch between the Option your unapply returns (which contains a single string) and the match in your case statement (with wants to match against a pair).
You could include a null check just to make sure (the compiler does, for case class companion objects):
class Abc(val age: Int, val name: String)
object Abc {
def unapply(obj: Abc): Option[(Int, String)] =
if (obj == null)
None
else
Some((obj.age, obj.name))
}
Shameless self-promotion: If you're interested in more details of pattern matching, you might find my little presentation "Everything you always wanted to know about pattern matching" useful.
If you want to create a custom class which has a unapply method and want to use the Extractor Pattern with it, the following rules should apply:
The return type of an unapply should be chosen as follows:
If it is just a test, return a Boolean. For instance case even()
If it returns a single sub-value of type T, return an Option[T]
If you want to return several sub-values T1,...,Tn, group them in an optional
tuple Option[(T1,...,Tn)].
Generally, this means that for you example all that needs to be done with the unapply method is the third option, which returns a tuple of values. Following that, unlike the case class which automatically creates immutable fields for you, you'll need to add the val annotation to you class declaration.
class abc (val age: Int, val name: String)
And:
def unapply(obj: abc): Option[(Int, String)] = Some((obj.age, obj.name))

extracting type parameters in scala

I have a piece of code that matches on a case class and then invokes a function based on the type and an extracted value:
def resolveByType[T](ids: List[Any]) = ids map (id => resolver.resolve[T](id))
override def resolve(deferred: Vector[Deferred[Any]], ctx: Any): Vector[Future[Any]] = deferred flatMap {
case DeferAccounts(ids) => resolveByType[Account](ids)
case DeferLocations(ids) => resolveByType[Location](ids)
case DeferDelegates(ids) => resolveByType[EconomicUnit](ids)
case DeferMUs(ids) => resolveByType[MunicipalUnit](ids)
case _ =>
List(Future.fromTry(Try(List[Any]())))
}
The case classes are defined as follows
case class DeferAccounts(accounts: List[String]) extends Deferred[List[Option[Account]]]
case class DeferLocations(loctions: List[String]) extends Deferred[List[Option[Location]]]
case class DeferDelegates(delegates: List[String]) extends Deferred[List[Option[EconomicUnit]]]
case class DeferMUs(delegates: List[String]) extends Deferred[List[Option[MunicipalUnit]]]
As you can see, all I need is that inner type parameter and the list. I'm trying to figure out the most scala-y way to do this. Seems like a lot of boilerplate code right now. Is there a clean way to extract the list and type parameter programmatically instead of declaratively, as it's being done now, or is this the correct way to do this?