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

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.

Related

passing multiple datatypes to Type variable

I am trying to pass either Grass or Rice object. But, it fails in compiling. I tried below Either[] option based on this link using Either. But, its not working.
I want to restrict passing Fish Object like this. I want to pass only Rice or Grass.
(new Cow).eat(new Fish) // I don't want this to happen
Please let me know why Either is not working here.
object AbstractType {
def main(args: Array[String]): Unit = {
(new Cow).eat(new Grass) // Error here -- type mismatch; found : Grass required: scala.util.Either[Grass,Rice]
}
}
abstract class Animal{
type FoodType <: Food
def eat(food : FoodType)
}
class Food{}
class Grass extends Food
class Rice extends Food
class Fish extends Food{}
class Cow extends Animal{
type FoodType = Either[Grass,Rice] // instead of Either[], keeping Grass here is compiling successfully as expected.
def eat(food : FoodType) {
println("Cow eats")
}
}
I tried below approach as suggested by slouc. But, even this approach not able to restrict this. (new Cow).eat(Fish()).
object AbstractType {
def main(args: Array[String]): Unit = {
(new Cow).eat(Grass())
}
}
abstract class Animal{
type FoodType <: Food
def eat(food : FoodType)
}
sealed trait Food
final case class Grass() extends Food
final case class Rice() extends Food
final case class Fish() extends Food
class Cow extends Animal{
type FoodType = //fill here
def eat(food : FoodType) {
println("Cow eats")
}
}
My Question : what will be the better approach to fill in the above code so that, I can pass only Rice or Grass object.(if not with either , how to achieve other way) and restrict Fish object.
This would work:
(new Cow).eat(Left[Grass, Rice](new Grass))
but you have another problem - you defined your abstract class Animal to expect a type FoodType which is a subtype of Food. Types Grass and Rice are both individually valid subtypes of Food, but Either[Grass, Rice] is not.
A bit of underlying theory:
When you work with a type that takes one out of several possible forms, that's called a sum type. As opposed to a product type, which combines all of the given types into one entity (e.g. Person consists of string first name, string last name, integer age etc.), a sum type only takes one materialization out of all the possible ones. This is what you have - your FoodType is either Grass or Rice or Fish.
Your problem here is that you're approaching your sum type with two different constructs which both serve the same purpose of modelling sum types. One approach is having a trait or an abstract class which is then extended by all the possible options:
trait Food
class Grass extends Food
class Rice extends Food
class Fish extends Food
Another approach is using an out-of-the-box sum type such as Either. Clumsy thing with Either is the fact that it only takes two possibilities, so for three you would have to have e.g. Either[Grass, Either[Rice, Fish]]. In some common Scala libraries such as scalaz or cats there are other, more suitable constructs for sum types (also known as "coproducts"), but let's not go into that now.
So, what you need to do is decide whether you want to stick to subtyping or you want to go with Either. For your use case subtyping is completely fine, so just remove the Either and implement type FoodType as e.g. Grass and it will work, as you noted yourself in the comment on the same line.
BTW your Food is a class, but notice how I said "trait or an abstract class". This is the best practice principle; if you're not expecting to ever need an instance of Food itself via new Food (and you're not; you're only going to instantiate its subclasses, e.g. new Grass), then it's better to not allow such instantiation in the first place.
Another hint is to make such trait / abstract class sealed and the subtypes final case class, which means that nobody else can ever provide extra options (that is, introduce some own custom food):
sealed trait Food
final case class Grass extends Food
final case class Rice extends Food
final case class Fish extends Food
Case class (as opposed to standard class) server the purpose of defining some stuff for you out of the box, such as
methods like equals(), copy() etc.
support for pattern matching (by implementing apply/unapply for you)
default companion object, which allows you to use Grass() instead of new Grass()
etc.
But OK I'm diverging :) hopefully this helps.
EDIT:
OK, now I realised your actual problem. You need to introduce another sum type. You already have Food, but now you need "cow food". You can easily model it exactly like that, adding a CowFood trait that extends Food and is extended by Grass and Rice.
sealed trait Food
sealed trait CowFood extends Food
sealed trait HorseFood extends Food
sealed trait SealFood extends Food
final case class Grass() extends CowFood with HorseFood
final case class Rice() extends CowFood
final case class Fish() extends SealFood
...
type FoodType = CowFood
(remember that traits are stackable; grass is both cow food and horse food)
I'm not a huge fan of subtyping, but for this particular problem it's a cleaner solution than getting entangled in Eithers and mapping all around the place.
In the code above, FoodType is defined twice, and it's definition in Cow shadows the one in Animal - this are two different types. You don't need Either in this case. You can define eat method with parameter of type Food, and just pass Grass, Rice or Fish, as all this classes inherit from Food
The example does not compile, because it expects parameter of type Either[Grass, Rice], but parameter of type Grass is passed.

Scala types: Class A is not equal to the T where T is: type T = A

I was reading the section 20.7 of the book Programming in Scala and I was wondering why while this code compiles:
class Food
class Fish extends Food
class Grass extends Food
abstract class Animal {
type SuitableFood <: Food
def eat(food: SuitableFood)
}
class Cow extends Animal {
type SuitableFood = Grass
override def eat(food: Grass) {}
}
val bessy: Animal = new Cow
bessy eat (new bessy.SuitableFood)
This code does not (the rest of the code is the same as before, only the last line changes):
bessy eat (new Grass)
And as far as I understand the type of Grass is the same of Cow.SuitableFood.
Also, I have another question regarding this example:
If bessy is of type Animal, how can the compiler know that it needs a type SuitableFood -> Grass instead of a type Food? 'Cause trying to provide a new Food gives me a compile error of type mismatch, but the class Animal needs a type Food and the type of bessy is explicitly defined: Animal
It's because bessie is declared Animal rather than Cow. bessie.SuitableFood is a "path-dependent type" (see below).
Try this:
val clarabelle: Cow = new Cow
clarabelle eat (new Grass)
This works because the compiler can deduce that clarabelle.SuitableFood = Grass from clarabelle's declared type.
Since bessie is declared Animal, not Cow, the compiler can't safely deduce that bessie.SuitableFood = Grass.* When you say new bessie.SuitableFood, the compiler generates code to look at the actual bessie object and generate a new instance of the appropriate type. bessie.SuitableFood is a "path-dependent type": the "path" (the bessie. part) that leads to the last identifier (SuitableFood) is actually part of the type. This enables you to have a custom version of a type for each individual object of the same class.
*Well, actually, I think that if the compiler were a little smarter, it could deduce that bessie.SuitableFood = Grass, since bessie is a val, not a var, and therefore won't change its type. In other words, the compiler ought to know that even though bessie is declared Animal, she's really a Cow. Perhaps a future version of the compiler will make use of this knowledge, and perhaps there's a good reason why that wouldn't be a good idea, which someone more expert than I will tell us. (Postscript: One just did! See Travis Brown's comment below.)
Regarding the second part of your question: it doesn't. Animal doesn't specify that its food is Food, but some subtype of Food. Would the compiler accept this, code like your example would compile, and wrongly so. The compiler doesn't know that the necessary subtype is Grass (which is why eat(new Grass) doesn't work either), it just knows that there are some foods your cow can't eat and is cautious about it.
I believe bessy eat (new bessy.SuitableFood) compiling is a bug (which was fixed in 2.11). Because another subtype of Animal could have a SuitableFood for which new makes no sense, e.g. type SuitableFood = Food or even type SuitableFood = Food with Int (Food with Int is a perfectly nice subtype of Food!).

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 _ =>
}

Abstract type vs. type parameter - where is the difference? [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Scala: Abstract Types vs Generics
Chapter 20.6 'Abstract types' of 'Programming in Scala' explains the use of an abstract type with an example that ends in the following resulting code:
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) {}
}
With these definitions, an object of Cow can not eat a fish:
class Fish extends Food
val bessy: Animal = new Cow
bessy eat (new Fish) // Error, type mismatch
After reading this good example about the use of an abstract type, I was wondering, why we do not just use a type parameter instead ?
class Food
abstract class Animal[T <: Food] {
def eat(food: T)
}
class Grass extends Food
class Cow extends Animal[Grass] {
override def eat(food: Grass){}
}
class Fish extends Food
val bessy: Animal[Grass] = new Cow
bessy eat (new Fish) // Also ends in a type mismatch error !
Where is the difference using type parameter instead of an abstract type here ?
Martin Odersky answered that question in this interview.
There have always been two notions of abstraction: parameterization and abstract members. In Java you also have both, but
it depends on what you are abstracting over. In Java you have abstract
methods, but you can't pass a method as a parameter. You don't have
abstract fields, but you can pass a value as a parameter. And
similarly you don't have abstract type members, but you can specify a
type as a parameter. So in Java you also have all three of these, but
there's a distinction about what abstraction principle you can use for
what kinds of things. And you could argue that this distinction is
fairly arbitrary.
What we did in Scala was try to be more complete and orthogonal. We decided to have the same construction principles for all three
sorts of members. So you can have abstract fields as well as value
parameters. You can pass methods (or "functions") as parameters, or
you can abstract over them. You can specify types as parameters, or
you can abstract over them. And what we get conceptually is that we
can model one in terms of the other. At least in principle, we can
express every sort of parameterization as a form of object-oriented
abstraction. So in a sense you could say Scala is a more orthogonal
and complete language.
That said, there are some subtle differences between the two, but I can't recall them off the top of my head.
You might also want to have a look at this thread.

Best way to use type classes with list parametrized with some base class, abstract class or trait

I think it would be easier to describe a problem with concrete example. Suppose I have have Fruit class hierarchy and Show type class:
trait Fruit
case class Apple extends Fruit
case class Orange extends Fruit
trait Show[T] {
def show(target: T): String
}
object Show {
implicit object AppleShow extends Show[Apple] {
def show(apple: Apple) = "Standard apple"
}
implicit object OrangeShow extends Show[Orange] {
def show(orange: Orange) = "Standard orange"
}
}
def getAsString[T](target: T)(implicit s: Show[T]) = s show target
I also have list of fruits that I would like to show to the user using Show (this is my main goal in this question):
val basket = List[Fruit](Apple(), Orange())
def printList[T](list: List[T])(implicit s: Show[T]) =
list foreach (f => println(s show f))
printList(basket)
This will not compile because List is parametrized with Fruit and I have not defined any Show[Fruit]. What is the best way to achieve my goal using type classes?
I tried to find solution for this problem, but unfortunately have not found any nice one yet. It's not enough to know s in printList function - somehow it needs to know Show[T] for each element of the list. This means, that in order to be able to make this, we need some run-time mechanism in addition to the compile-time one. This gave me an idea of some kind of run-time dictionary, that knows, how to find correspondent Show[T] at run-time.
Implementation of implicit Show[Fruit]can serve as such dictionary:
implicit object FruitShow extends Show[Fruit] {
def show(f: Fruit) = f match {
case a: Apple => getAsString(a)
case o: Orange => getAsString(o)
}
}
And actually very similar approach can be found in haskell. As an example, we can look at Eq implementation for Maybe:
instance (Eq m) => Eq (Maybe m) where
Just x == Just y = x == y
Nothing == Nothing = True
_ == _ = False
The big problem with this solution, is that if I will add new subclass of Fruit like this:
case class Banana extends Fruit
object Banana {
implicit object BananaShow extends Show[Banana] {
def show(banana: Banana) = "New banana"
}
}
and will try to print my basket:
val basket = List[Fruit](Apple(), Orange(), Banana())
printList(basket)
then scala.MatchError would be thrown because my dictionary does not know anything about bananas yet. Of course, I can provide updated dictionary in some context that knows about bananas:
implicit object NewFruitShow extends Show[Fruit] {
def show(f: Fruit) = f match {
case b: Banana => getAsString(b)
case otherFruit => Show.FruitShow.show(otherFruit)
}
}
But this solution is far from perfect. Just imagine that some other library provides another fruit with it's own version of dictionary. It will just conflict with NewFruitShow if I try to use them together.
Maybe I'm missing something obvious?
Update
As #Eric noticed, there is one more solution described here: forall in Scala . It's really looks very interesting. But I see one problem with this solution.
If I use ShowBox, then it will remember concrete type class during it's creation time. So I generally building list with objects and correspondent type classes (so dictionary in present in the list). From the other hand, scala has very nice feature: I can drop new implicits in the current scope and they will override defaults. So I can define alternative string representation for the classes like:
object CompactShow {
implicit object AppleCompactShow extends Show[Apple] {
def show(apple: Apple) = "SA"
}
implicit object OrangeCompactShow extends Show[Orange] {
def show(orange: Orange) = "SO"
}
}
and then just import it in current scope with import CompactShow._. In this case AppleCompactShow and OrangeCompactShow object would be implicitly used instead of defaults defined in the companion object of Show. And as you can guess, list creation and printing happens in different places. If I will use ShowBox, than most probably I will capture default instances of type class. I would like to capture them at the last possible moment - the moment when I call printList, because I even don't know, whether my List[Fruit] will ever be shown or how it would be shown, in the code that creates it.
The most obvious answer is to use a sealed trait Fruit and a Show[Fruit]. That way your pattern matches will complain at compile time when the match is not exhaustive. Of course, adding a new kind of Fruit in an external library will not be possible, but this is inherent in the nature of things. This is the "expression problem".
You could also stick the Show instance on the Fruit trait:
trait Fruit { self =>
def show: Show[self.type]
}
case class Apple() extends Fruit { self =>
def show: Show[self.type] = showA
}
Or, you know, stop subtyping and use type classes instead.