Does mutation break contravariance in the same way it breaks covariance? - covariance

Mutative covariant containers are unsound.
For example, and using no language in particular,
interface Pet;
class Cat extends Pet { meow(); }
class Dog extends Pet { woof(); }
class Box[T] {
value: T;
}
var dog: Box[Dog] = new Box(new Dog);
var pet: Box[Pet] = dog;
pet.value = new Cat;
dog.woof(); // uh oh!
Is there an analogous unsoundness with contravariant types?
My intuition is no. Loosely, the above unsoundness comes from the fact that a Box[T] "contains" a reference to a T, but a contravariant type like Predicate[T] does not "contain" anything at all.
However, I can't find much on the subjet.

Related

Advantage of Upper Bound over Subtyping in Scala

I know this question has been asked before here. But the answers there do not satisfy my doubt.
I was told that they prevent mix-up of class types, the code below shows that they're not mixed up at all.
So, it shouldn't matter right?
Classes:
package Practice
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"
}
Here is the real confusion:
//Class with Upper Bound
class PetContainer[P <: Pet](p: P) {
def pet: P = p
}
//Class with Subtyping(Or Upcasting, I think they're the same)
class SimplePetContainer(p: Pet){
def pet: Pet = p
}
Driver Code:
val CatContainer: PetContainer[Cat] = new PetContainer[Cat](new Cat)
val DogContainer: SimplePetContainer = new SimplePetContainer(new Dog
println(CatContainer.pet.getClass)
println(DogContainer.pet.getClass)
Output:
class Practice.Cat
class Practice.Dog
//Practice was the package
Like I mentioned before, the classes are preserved.
So my question is, What advantage does Upper Bound have on Subtyping?
With your CatContainer, you know that CatContainer.pet is a Cat at compile-time. Meaning that the compiler also knows that. So you can say
CatContainer.pet.meow()
For the SimplePetContainer you do not have static type information about the pet inside anymore.
Like I mentioned before, the classes are preserved.
At runtime, the pet of course still knows its type (well, almost, it knows its class, which in your case would have been enough, any extra type information such as the generic types of that class has been erased).
But the variable DogContainer.pet lacks information about what sort of Pet it contains.
I was told that they prevent mix-up of class types
The compiler won't stop you from writing
val DogContainer = new SimplePetContainer(new Cat())
but it will reject this
val DogContainer = new PetContainer[Dog](new Cat())

Dynamic polymorphism in Scala

I need to change an object's behavior on run-time.
I have two concrete object (singleton) classes Dog and Cat, both extend from an abstract class Animal.
The object animal of Animal type should be changed to either Dog or Cat on runtime.
Here's the rough code of something that I am trying to accomplish:
abstract class Animal() {
def sound: Unit
}
object Cat extends Animal {
def sound: Unit = {
print("meow")
}
}
object Dog extends Animal {
def sound: Unit = {
print("bark")
}
}
object MyProgram {
val animal: Animal = _
def initialize(config: Config): Unit ={
// check the config
if (config.getString("ANIMAL_TYPE").equals("Dog")) {
animal = Dog
} else {
animal = Cat
}
}
def run: Unit = {
animal.sound
}
}
def main(): Unit = {
val config = ConfigFactory.praseFile(myconfigfile)
MyProgram.initialize(config)
MyProgram.run
}
Can something like this be done in Scala? If not, how can I accomplish this in Scala.
The error you are getting has nothing to do with typing or dynamic polymorphism:
var animal : Animal = _
^
On line 19: error: local variables must be initialized
As you can see, there is nothing wrong with the types in your program, you simply need to properly initialize your variable:
def main() : Unit = {
var animal = if(config.getString("ANIMAL_TYPE").equals("Dog")) {
Dog
} else {
Cat
}
// this should print either bark or meow
animal.sound
}
Note that there are a couple of non-idiomatic things in your code. A more idiomatic version would look something like this:
trait Animal {
val sound: String
}
object Cat extends Animal {
override val sound = "meow"
}
object Dog extends Animal {
override val sound = "bark"
}
def main(): Unit = {
val animal = if (config.getString("ANIMAL_TYPE").equals("Dog")) Dog else Cat
// this should print either bark or meow
print(animal.sound)
}
Use a trait instead of an abstract class.
Don't use an empty constructor / initializer, just use no constructor / initializer.
Separate input/output from computation: the printing should be done in the main method, not in the Animal.
Use the explicit override modifier.
Don't use type annotations if the type is obvious.
Don't use curly braces around single expressions.
Don't use var, always use val.
if is an expression, don't ignore its return value.
You are defining the main function incorrectly.
The main function should be a member of some object, and it should have an argument of the type Array[String].
object SomeRandomName {
def main(): Unit = {
var animal: Animal = null
// check the config
if(config.getString("ANIMAL_TYPE").equals("Dog")) {
animal = Dog
} else {
animal = Cat
}
// this should print either bark or meow
animal.sound
}
}
And this code should compile and run well.
SIDENOTE: If you are using Scala 3 (instead of Scala 2.x), then you don't need to make a wrapper object of the main function. The function can be at the top level.
Your code should work almost as it is, just assign something to animal.
object MyProgram {
//First of all use some default value for animal.
//It will be safer to use.
var animal: Animal = Cat
// or use explicitly null if there is no sensible default value.
// underscore makes it less clear what will happen.
//var animal: Animal = null
//I thing match is better than if/else here especially when third animal will arrive. You can assign it like that:
def initialize(config: Config): Unit ={
animal = (config.getString("ANIMAL_TYPE") match {
case "Dog" => Dog
case _ => Cat
}
}
}

scala ADTs via sealed traits - is there a way to deserialize from string in a generic fashion

Let's say I have the following trait
trait Named {
def name: String
}
and the following Algebraic Data Type
sealed trait Animal extends Named
case object Dog extends Animal {
override val name: String = "dog man"
}
case object Cat extends Animal {
override val name: String = "cat man"
}
case object Owl extends Animal {
override val name: String = "I am an owl left in the dark"
}
Now, I can deserialize an instance of string into my Animal ADT with the following method.
object Animal {
def apply(name: String): Animal = name match {
case Dog.name => Dog
case Cat.name => Cat
}
}
#oxbow_lakes mentions at the end of his answer that:
Can't instantiate easily from persisted value. This is also true but,
except in the case of huge enumerations (for example, all currencies),
this doesn't present a huge overhead.
I find that the fact that when you add a new value it needs to be added to the deserialization code explicitly as error prone (I thought that the compiler would warn me of an in-exhaustive match, but take a look at Owl above and the apply method - there was no warning issued...)
Is there no better way? (If not with the standard scala toolset, a third party one?)
This problem already solved by enumeratum library:
https://github.com/lloydmeta/enumeratum
Your code could be written like this:
import enumeratum._
import enumeratum.EnumEntry.Lowercase
sealed trait Animal extends EnumEntry with Lowercase
object Animal extends Enum[Animal] {
val values = findValues
case object Dog extends Animal
case object Cat extends Animal
case object Owl extends Animal
}
val dogName = Animal.Dog.entryName
val dog = Animal.withNameInsensitive(dogName)
One thing you could try is to use reflection to obtain the set of types that extend Animal, then use that to create a Map[String,Animal] using name to lookup object values, then use the map in your Animal.apply function.
Refer to this question for more information on obtaining the Animal subclasses.

Why is the best way to avoid being trapped by Scala's abstract type refinement?

I have a basic example from chapter 20.7 of Programming in Scala (Martin Odersky, Lex Spoon and Bill Venners), on the topic of Abstract Types. The code below is from Listing 20.10, except that I added the two last lines which seem ostensibly implied by the previous example:
class Food
abstract class Animal {
type SuitableFood <: Food
def eat(food: SuitableFood)
}
class Grass extends Food
class Cow extends Animal {
type SuitableFood = Grass
override def eat(food: Grass) {}
}
class Fish extends Food
val bossy: Animal = new Cow // If the compiler were helpful, this would error.
bossy.eat(new Grass) // error!
// type mismatch; found: Grass, required: bossy.SuitableFood
As I stated above, the two lines where bossy is declared as an Animal are not actually in the example, but seem a very reasonable conceptual leap. At the level of the abstract class Animal (the declared type of bossy), the type member SuitableFood is still abstract. So, nothing will satisfy the compiler, even though it looks as if it wants a path-dependent-type at the method call.
If I declare my val to be of type Cow, the method call works, as follows:
val bessy: Cow = new Cow
bessy.eat(new Grass) // happy-happy
Given that there is nothing I could put in the 'eat()' method call for bossy (declared as an Animal) to satisfy the compiler, why does the compiler even allow bossy to be declared as an Animal/instantiated as a Cow? In other words, what possible use allowing the object declaration/instantiation, but not the method call, have?
Are there "best practices" for this feature in Scala, given that abstract member type refining seems to deliberately allow something normally forbidden in OO programming? Perhaps someone has found a killer-use?
I very much desire to see this behavior as something that makes perfect sense. What is the motivating use-case for this feature, i.e., declaring an abstract type, then refining that type in a derived class such that the subtype has a more refined type than the supertype?
Given that there is nothing I could put in the 'eat()' method call for bossy (declared as an Animal) to satisfy the compiler, why does the compiler even allow bossy to be declared as an Animal/instantiated as a Cow?
There is: bossy.eat((new Grass).asInstanceOf[bossy.SuitableFood]). Of course, this doesn't mean you should ever write code like this.
Even if there weren't, there are a lot of things you can do with bossy without calling eat method: put it into a List, get its hash code, etc. etc.
You can still do other useful stuff. You can make an Animal eat Food if you can prove that it is SuitableFood.
When you can make an Animal throw up, you know that everything he throws up is something he can eat, because he's eaten is before. And you know it's Food even if you don't know for sure whether it's Grass or Fish. So you can do operations on it that are possible for every type of Food.
scala> :paste
// Entering paste mode (ctrl-D to finish)
abstract class Food { def name: String }
class Grass extends Food { def name = "Grass" }
abstract class Animal {
type SuitableFood <: Food
def eat(food: SuitableFood): Unit
def throwUp: Option[SuitableFood]
}
class Cow extends Animal {
type SuitableFood = Grass
private[this] var digesting: List[Grass] = Nil
def eat(food: Grass) {
digesting = food :: digesting
}
def throwUp = digesting match {
case Nil => None
case food :: rest =>
digesting = rest
Some(food)
}
}
def dispose(food: Food) = println(s"Disposing of some ${food.name}.")
// Exiting paste mode, now interpreting.
scala> val animal: Animal = { val cow = new Cow; cow.eat(new Grass); cow }
animal: Animal = Cow#506dcf55
scala> animal.throwUp foreach animal.eat // can eat his own vomit :s
scala> animal.throwUp foreach dispose // I can dispose of all food
Disposing of some Grass.

Scala factory pattern returns unusable abstract type

Please let me know how to make the following bit of code work as intended. The problem is that the Scala compiler doesn't understand that my factory is returning a concrete class, so my object can't be used later. Can TypeTags or type parameters help? Or do I need to refactor the code some other way? I'm (obviously) new to Scala.
trait Animal
trait DomesticatedAnimal extends Animal
trait Pet extends DomesticatedAnimal {var name: String = _}
class Wolf extends Animal
class Cow extends DomesticatedAnimal
class Dog extends Pet
object Animal {
def apply(aType: String) = {
aType match {
case "wolf" => new Wolf
case "cow" => new Cow
case "dog" => new Dog
}
}
}
def name(a: Pet, name: String) {
a.name = name
println(a +"'s name is: " + a.name)
}
val d = Animal("dog")
name(d, "fred")
The last line of code fails because the compiler thinks d is an Animal, not a Dog.
You should create companion objects with apply method for each subclass of Animal instaed of Animal trait. Also, it is considered a bad practice to use mutable field like you did with name.
You can do that, without changing anything else :
val d = Animal("dog").asInstanceOf[Dog] //> d : Test.Dog = Test$$anonfun$main$1$Dog$1#1030dda
name(d, "fred") //> Test$$anonfun$main$1$Dog$1#1030dda's name is: fred
But, i don't think it's a very good idea...
I don't want to sound rude but the compiler is right about assuming that d is an Animal because that's what the Animal.apply method returns.
As already pointed out you could force the type of d with an explicit cast but it simply wouldn't be type safe. It would be leveraging your knowledge about the method implementation as a programmer, which will eventually become a source of bugs as your codebase grows and you possibly change previous code in unexpected ways.
If you need to call a Pet method then you would better use a factory method that creates Pet objects, or at least check the object type before doing the type cast, using
if (d.isInstanceOf[Pet]) name(d.asInstanceOf[Pet], "Fred")
Or better still, using pattern matching
val d = Animal("dog")
d match {
case p: Pet => name(p, "fred")
case _ =>
}