I am trying to create a List of classes, like this:
abstract class Animal {
def name = this.getClass.getName
def say: String
}
class Dog extends Animal {
def say = "Woof"
}
class Cat extends Animal {
def say = "Meow"
}
val animalClasses = List(Dog, Cat)
This falls over on the last line, with the error message:
Zoo.scala:18: error: not found: value Dog
Note that I could create a List of instances of classes easily with List(new Dog(), new Cat()), but that's not what I want.
There you go:
scala> List(classOf[Dog],classOf[Cat])
res1: List[Class[_ >: Cat with Dog <: Animal]] = List(class Dog, class Cat)
As per this:
The predefined function classOf[T] returns a runtime representation of the Scala class type T.
Related
In a typical Scala upperbound example
abstract class Animal {
def name: String
}
abstract class Pet extends Animal {}
class Cat extends Pet {
override def name: String = "Cat"
}
class Dog extends Pet {
override def name: String = "Dog"
}
class Lion extends Animal {
override def name: String = "Lion"
}
What is the difference between this
class PetContainer[P <: Pet](p: P) {
def pet: P = p
}
val dogContainer = new PetContainer[Dog](new Dog)
val catContainer = new PetContainer[Cat](new Cat)
and this?
class PetContainer1(p: Pet) {
def pet: Pet = p
}
val dogContainer1 = new PetContainer1(new Dog)
val catContainer1 = new PetContainer1(new Cat)
What is the advantage of using an upper type bound vs using the abstract class/trait directly?
With upper bound you can have a collection of specific subtype - so limiting to only cats or dogs and you can get a specific subtype back from def pet. It's not true for PetContainer1.
Losing more accurate type info example:
val doggo: Dog = new Dog
val dogContainer1 = new PetContainer1(doggo)
// the following won't compile
// val getDoggoBack: Dog = dogContainer1.pet
val dogContainer2 = new PetContainer[Dog](doggo)
// that works
val getDoggoBack: Dog = dogContainer2.pet
You can't put a cat into dog container:
// this will not compile
new PetContainer[Dog](new Cat)
It would get more significant if you would be dealing with collections of multiple elements.
The main difference between the two is actually the difference between these two types:
def pet: P = p
// and
def pet: Pet = p
So, in the first example, the type of pet is P, and in the second example, the type of pet is Pet. In other words: in the first example, the type is more precise, since it is a specific subtype of Pet.
If I put a Dog in the PetContainer[Dog], I get a Dog back out. Whereas, if I put a Dog in the PetContainer1, I get back a Pet, which could be either a Cat or a Dog, or something else entirely. (You haven't made your classes sealed or final, so someone else could come along, and create their own subclass of Pet.)
If you use an editor or IDE which shows you the types of expressions, or you try your code in the REPL or in Scastie, you actually see the difference:
dogContainer.pet // has type `Dog`
catContainer.pet // has type `Cat`
dogContainer1.pet // has type `Pet`
catContainer1.pet // has type `Pet`
See Scastie link for an example:
sealed trait Animal:
val name: String
sealed trait Pet extends Animal
case object Cat extends Pet:
override val name = "Cat"
case object Dog extends Pet:
override val name = "Dog"
case object Lion extends Animal:
override val name = "Lion"
final case class PetContainer[+P <: Pet](pet: P)
val dogContainer = PetContainer(Dog)
val catContainer = PetContainer(Cat)
final case class PetContainer1(pet: Pet)
val dogContainer1 = PetContainer1(Dog)
val catContainer1 = PetContainer1(Cat)
dogContainer.pet //=> Dog: Dog
catContainer.pet //=> Cat: Cat
dogContainer1.pet //=> Dog: Pet
catContainer1.pet //=> Cat: Pet
This gets more interesting if, say, you have a kennel that can hold two pets:
sealed trait Pet:
val name: String
case object Cat extends Pet:
override val name = "Cat"
case object Mouse extends Pet:
override val name = "Mouse"
final case class UnsafePetKennel(pet1: Pet, pet2: Pet)
val unsafeCatKennel = UnsafePetKennel(Cat, Cat)
val unsafeMouseKennel = UnsafePetKennel(Mouse, Mouse)
val oopsSomeoneAteMyMouse = UnsafePetKennel(Cat, Mouse)
final case class SafePetKennel[+P <: Pet](pet1: P, pet2: P)
val safeCatKennel = SafePetKennel[Cat.type](Cat, Cat)
val safeMouseKennel = SafePetKennel[Mouse.type](Mouse, Mouse)
val mouseIsSafe = SafePetKennel[Cat.type](Cat, Mouse)
// Type error: found `Mouse`, required `Cat`
val mouseStillSafe = SafePetKennel[Mouse.type](Cat, Mouse)
// Type error: found `Cat`, required `Mouse`
Scastie link
Unfortunately, things can still go wrong if we rely on Scala's type parameter inference:
val inferredKennel = SafePetKennel(Cat, Mouse)
works, because Scala infers P to be the least upper bound of Cat and Mouse, which is Pet, and thus inferredKennel has type SafePetKennel[Pet], and since both Cat and Mouse are subtypes of Pet, this is allowed.
We can fix that with a slight modification to our SafePetKennel:
final case class SaferKennel[+P <: Pet, +Q <: Pet](
pet1: P, pet2: Q)(implicit ev: P =:= Q)
val inferredKennel = SaferKennel(Cat, Mouse)
// Cannot prove that Cat =:= Mouse.
Scastie link
Let's say I have this hierarchy:
sealed trait Animal {
def eat = println("eating!")
}
final case class Dog(name :String) extends Animal {override def eat= println("dog eating")}
final case class Cat(name: String) extends Animal {override def eat= println("cat eating")}
As you see I'm using akka http and circe, then I have the following:
import io.circe.syntax._
import io.circe.Json
...
pathPrefix("path" / "something") {
post {
entityAs[Map[String,Json]] { data =>
// depending on the key of the map I will create an object Dog or Animal
val transformed = data.map { d =>
d._1 match {
case "dog" => d._2.as[Dog]
case "cat" => d._2.as[Cat]
}
}
// then I will do something like
transformed.foreach(_.eat)
complete(Status.OK)
}
}
But for some reason I can't use the method eat.
And I see that the type of transformed is immutable.Iterable[Result[_ >: Dog with Cat <: Animal]] I guess that's the problem that prevent me to call eat method.
Is there anyway to fix that to be able to call the eat event?
As you noticed, the value you are getting is:
Iterable[Result[_ >: Dog with Cat <: Animal with Product]]
while:
final type Result[A] = Either[DecodingFailure, A]
In order to access the eat method, you have to do:
transformed.foreach(_.map(_.eat))
From you point of view, every time when map key is dog, its value is Dog class, but from compiler doesn't know about that.
That is why transformed is Iterable[Result[X]], and when traversing iterable you are trying to call eat method on Result type.
You have to extract value from Result object, only if it was deserialized correctly
In order to understand how 'implicit' works in Scala, I have written following code but it doesn't give me the expected result.
I thought I understood the use of 'implicit' (which clearly is not true). I have three classes, Plant, Dog and myPet. Dog has a function 'sound' which returns "woof". Plant has a function "tallOrShort" which returns "tall". These functions describe features of Dog and Plant.
I want to write a generic code in myPet to which I can pass an instance of Dog or Plant. I call this function 'describe'. The describe function should print "woof" for Dog instances and "tall" for Plant instances.
Dog and Plant are independent classes (no subtype). I thought I can use 'implicit' to "add" this functionality in Dog and Plant class. My understanding is that by using implicit, Dog or Plant could be implicitly converted into 'something' which can then call 'sound' or 'tallOrShort' for Dog and Plant respectively. I have written following code but it doesn't work.
I started with Dog class to begin with
//create Dog
scala> class Dog {
| def sound = "woof"
| }
defined class Dog
//create trait (the contract interface which Dog can be member of
scala> trait myPetTrait[A] {
| def describePet(a:A):String
| }
defined trait myPetTrait
//implicit conversion should happen using this code?
scala> implicit object dogIsPet extends myPetTrait[Dog] {
| def describePet(d:Dog) = d.sound
| }
defined object dogIsPet
Now first, I thought of defining only a generic function 'describe' as follows but I am not able to pass Dog or Plant instance to it.
//'describe' function. It should work for both Dog and Plant
scala> def describe[A](implicit pt:myPetTrait[A]) = {println(pt.describePet(_:A))}
describe: [A](implicit pt: myPetTrait[A])Unit
scala> describe(new Dog)
<console>:21: error: type mismatch;
found : Dog
required: myPetTrait[?]
describe(new Dog)
Question 1 - What is wrong with above? Shouldn't Dog get converted to myPetTrait[Dog]?
Then I thought to create a class (myPet) and define 'describe' in that class. That doesn't work either
//metPet It should work for both Dog and Plant
scala> class myPet[A](a:A) {
| def describe[A](implicit pt:myPetTrait[A]) = {println(pt.describePet(_:A))}
| }
defined class myPet
scala> new myPet(new Dog).describe
<function1>
Question 2 - Why does this compile at least if I put describe in myPet? Why am I getting a function literal (function1), not the print I expect
To keep experimenting, I started REPL again and declared Plant as well before creating describe and myPet
//new REPL session. created Dog
scala> class Dog {
| def sound = "woof"
| }
defined class Dog
//created plant
scala> class Plant {
| def tallOrShort = "tall"
| }
defined class Plant
//created trait
scala> trait myPetTrait[A] {
| def describePet(a:A):String
| }
defined trait myPetTrait
//code which should I think help in implicit conversion
scala> implicit object plantIsPet extends myPetTrait[Plant] {
| def describePet(p:Plant) = p.tallOrShort
| }
defined object plantIsPet
//describe still doesn't work
//describe shuold work for both Plant and Animal
scala> def describe[A](implicit pt:myPetTrait[A]) = {println(pt.describePet(_:A))}
describe: [A](implicit pt: myPetTrait[A])Unit
//not sure why this error comes
scala> describe(new Dog)
<console>:21: error: type mismatch;
found : Dog
required: myPetTrait[?]
describe(new Dog)
//get ambiguity error in this line
scala> new myPet(new Dog).describe //myPet gives ambiguity error
I get ambiguous implicit values error stating that both object dogIsPet of type dogIsPet.type and object plantIsPet of type plantIsPet.type match expected type myPetTrait[A]
Question 3 - why does Scala complain of ambiguity? It is probably because dogIsPet.type and plantisPet.type are of same 'type'. How do I make this code work?
I think you missed this (describe must take a of type A and an implicit contract)
define describe like this in myPet
class myPet[A](a:A) {
def describe(implicit pt:myPetTrait[A]) = {
println(pt.describePet(a))
}
}
describe outside the myPet can be declared like this
def describe[A](a: A)(implicit pt:myPetTrait[A]) = {println(pt.describePet(a))}
Scala has a special syntax for this
def describe[A: myPetTrait](a: A) = println(implicitly[myPetTrait[A]].describePet(a))
Scala REPL
scala> def describe[A](a: A)(implicit pt:myPetTrait[A]) = {println(pt.describePet(a))}
describe: [A](a: A)(implicit pt: myPetTrait[A])Unit
scala> describe[Plant](new Plant)
tall
or use scala syntactic sugar
scala> def describe[A: myPetTrait](a: A) = println(implicitly[myPetTrait[A]].describePet(a))
describe: [A](a: A)(implicit evidence$1: myPetTrait[A])Unit
scala> describe[Plant](new Plant)
tall
scala> trait myPetTrait[A] { def describePet(a:A):String }
defined trait myPetTrait
scala> class Dog { def sound = "woof" }
defined class Dog
scala> implicit object dogIsPet extends myPetTrait[Dog] { def describePet(d:Dog) = d.sound }
defined object dogIsPet
scala> def describe[A: myPetTrait](a: A) = println(implicitly[myPetTrait[A]].describePet(a))
defined function describe
scala> implicit object dogIsPet extends myPetTrait[Dog] { def describePet(d:Dog) = d.sound }
defined object dogIsPet
scala> describe[Dog](new Dog)
woof
scala> class myPet[A](a:A) {
def describe(implicit pt:myPetTrait[A]) = {
println(pt.describePet(a))
}
}
defined class myPet
scala> new myPet[Dog](new Dog).describe
woof
Complete code at one place
Main.scala
object Implicits {
trait myPetTrait[A] {
def describePet(a:A):String
}
class Dog {
def sound = "woof"
}
class Plant {
def tallOrShort = "tall"
}
//evidence for Plant
implicit object plantIsPet extends myPetTrait[Plant] {
def describePet(p:Plant) = p.tallOrShort
}
//evidence for Dog
implicit object dogIsPet extends myPetTrait[Dog] {
def describePet(d:Dog) = d.sound
}
def describe[A](a: A)(implicit pt:myPetTrait[A]) = {
println(pt.describePet(a))
}
//syntactic sugar
def describe2[A : myPetTrait](a: A) =
println(implicitly[myPetTrait[A]].describePet(a))
class myPet[A](a:A) {
def describe(implicit pt:myPetTrait[A]) = {
println(pt.describePet(a))
}
}
}
object Main {
import Implicits._
def main(args: Array[String]): Unit = {
describe(new Dog)
describe(new Plant)
describe2(new Dog)
describe2(new Plant)
new myPet[Dog](new Dog).describe
new myPet[Plant](new Plant).describe
}
}
output:
woof
tall
woof
tall
woof
tall
So, what I want to do is to create an abstract inheritance model using traits. I think example code works best so I created this small showcase to present my problem.
trait Animals{
val owned: Seq[Animal]
type Animal <: TAnimal
trait TAnimal {
def name : String
}
}
So far so good. Now I have another trait "Dogs". The dogs are chipped so they have and identification Number. Also I want to implement the sequence containing all the dogs I have (lets say I have 5 dogs with random names and random identNo, for simplicities sake).
trait Dogs extends Animals{
type Dog <: TDog
val owned = ???
trait TDog extends TAnimal {
def identNo : Int
}
}
The Problem is, since Animal or Dog are only types I cannot create concrete instances of them.
I think I can use something like Seq.fill but I'm not able to create a matching expression.
This is called a Cake Pattern. And you don't need to write all this stuff in Dog trait, you can define it like this:
trait Animals{
type Animal <: TAnimal
def owned: Seq[Animal]
trait TAnimal {
def name : String
}
}
trait Dogs extends Animals{
type Animal <: TDog
trait TDog extends TAnimal {
def identNo : Int
}
}
Then "at the end of the world" you assemble your cake with some concrete implementation:
trait ReservoirDogs extends Dogs {
case class Animal(name: String, identNo: Int) extends TDog
val owned = List(Animal("Pink", 1), Animal("Blue", 2))
}
Now you can mix it in:
scala> val dogs = new Dogs with ReservoirDogs {}
dogs: Dogs with ReservoirDogs = $anon$1#6f6f6727
scala> val dogs = new Animals with ReservoirDogs {}
dogs: Animals with ReservoirDogs = $anon$1#11c8ce34
This is what Cake Pattern is all about
The Liskov Substitution Principle tells us that if A is a subtype of B than everything we can do with type B we should be able to do with type A.
So to investigate this further, I create the following:
class Animal
class Dog extends Animal
class BlueDog extends Dog
I understand why I am not allowed to do
val c: Array[Animal] = a
as Arrays are not covariant in Scala (like they are in Java).
But, I think I should be able to do:
val a: Array[Dog] = Array(new Dog())
val b: Array[BlueDog] = a
I would expect val b to be ok.
But I get:
class Array is invariant in type T. You may wish to investigate a wildcard type such as `_ >: ...
val a: Array[Dog] = Array(new Dog())
val b: Array[BlueDog] = a
Is a little strange, since your BlueDog is more strictly then Dog and may have other method.
class Animal
class Dog extends Animal
class BlueDog extends Dog {
def wolf() { println ("I'm a blue dog") }
}
Then what should the following code do?
val a: Array[Dog] = new Array(new Dog())
val b: Array[BlueDog] = a
b(0).wolf()
Well, your Dog in Array a does not have wolf() method....so it's clearly that you should not assign a parent type to subtype.
That's why the following works:
val dog: Dog = new BlueDog
But the following doesn't:
val blueDog: BlueDog = new Dog