passing multiple datatypes to Type variable - scala

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.

Related

scala value class multiple inheritance

I have in my project objects that represent IDs.
Let's say it is ChairId, TableId, LampId. I want them all to inherit from GenericId. And I want to be able to call def f(x: GenericId) = x.id
I want them to hold only single id: String so I would like to make them extend AnyVal.
Also I would like for each type to provide function generate which would generate my specific ID i.e. I would like to type something like ChairId.generate()
I have typed this:
sealed abstract class GenericId(val id: String)
final case class ChairId(override val id: String) extends GenericId(id)
final case class TableId(override val id: String) extends GenericId(id
And I though if GenericId would inherit from AnyVal that would work but so far no luck ;/ I also tried making GenericId a trait and make case classes extend AnyVal with GenericId but also won't compile :/
Another thing with TableId.generate() I can provide companion object just with function generate and that basically solve my problem but I wondered if there is possibility to solve that without defining companion object? (i.e. through implicits somehow)
// edit
regarding comment to provide code which doesn't compile(and I would like to):
sealed abstract class AbstractId(val id: String) extends AnyVal
final case class CatId(override val id: String) extends AbstractId(id)
final case class DogId(override val id: String) extends AbstractId(id)
Value classes cannot work this way for a couple of reasons.
First, from the documentation, value classes cannot be extended by any other class, so AbstractId cannot extend AnyVal. (Limitation #7)
scala> abstract class AbstractId(val id: String) extends AnyVal
<console>:10: error: `abstract' modifier cannot be used with value classes
abstract class AbstractId(val id: String) extends AnyVal
^
Second, even if you make AbstractId a trait, and define the other ids like this:
final case class DogId(val id: String) extends AnyVal with AbstractId
.. the usage of the value class wouldn't fit your case, because the class itself would still get allocated. See the allocation summary:
A value class is actually instantiated when:
a value class is treated as another type.
a value class is assigned to an array.
doing runtime type tests, such as pattern matching.
Some quotes from the value classes SIP that are likely to clarify your doubts:
Value classes...
...must have only a primary constructor with exactly one public, val
parameter whose type is not a value class.
... cannot be extended by another class.
As per 1. it can not be abstract; per 2. your encoding doesn't work.
There is another caveat:
A value class can only extend universal traits and cannot be extended
itself. A universal trait is a trait that extends Any, only has defs
as members, and does no initialization. Universal traits allow basic
inheritance of methods for value classes, but they incur the overhead
of allocation.
With all that in mind, based on your last snippet, this might work:
sealed trait AbstractId extends Any { def id: String }
final case class CatId(id: String) extends AnyVal with AbstractId
final case class DogId(id: String) extends AnyVal with AbstractId
But keep in mind the allocation only occurs if you want to use CatId and DogId as an AbstractId. For better understanding I recommend reading the SIP.

Trait vs Abstract class in Scala with constructor parameters

What are the differences among these ways of defining Animal:
First way:
trait Animal {
def color: String
}
Second way:
trait Animal {
val color: String
}
Third way:
abstract class Animal(color: String) {}
Dog is a subclass of Animal. Consider the first way and the second way of defining Animal, what are the differences among the following ways of defining Dog:
First way:
case class Dog() extends Animal {
override def color:String = "black"
}
Second way:
case class Dog() extends Animal {
val color = "black"
}
Third way:
case class Dog(color: String) extends Animal {}
Forth way:
case class Dog(override val color: String) extends Animal(color) {}
Whoa, a lot to be answered here.
Regarding your first question, if you use a val then all subclasses must also use val. If you use def, subclasses can implement it either using def, val or lazy val. If color is a stable, immutable value, then declaring it as "val" in the trait makes sense since it imposes that all implementations in concrete subclasses will also be immutable.
The third way makes color only available in the constructor body and not visible from the outside. However, if you wrote
abstract class Animal(val color: String) {}
then it would be the same as the second way, only using abstract class instead of the trait. You could create a new animal and access its color attribute.
Regarding dog, defining color as def means that it will be computed every time it is invoked (i.e. when someone tries to access myDog.color). Defining it as val means that it will be an immutable value calculated once and for all when dog object is created. If it were a lazy val, then it would be calculated once and for all, but not when the dog is created, but when its color attribute is invoked (the calculation is postponed until the point of usage, hence the "lazy").
As I said above, if the Animal trait uses a val, then the Dog must also use a val. If Animal uses a def, then Dog can implement that as a def, val or lazy val.
Third way of writing a Dog is simply providing a parameter in case of writing an Animal with a class parameter (which was also third way in animal case). As I said earlier, in this case you cannot access the color attribute from the outside (that is, have val myDog = new Dog("blue") and access myDog.color).
Fourth way of writing a dog is implementing the Animal in case it was written in the way I have shown you above in the code (with using a val keyword). Now the color attribute will be visible. Override is not mandatory since you are implementing an abstract method, not overriding a concrete method, but you can leave it if you like (this way compiler will warn you if you, say, misspell "color" or someone removes the color from Animal class).
Perhaps this article can help too.

Scala: self type annotation

(Trying to understand the use of self types by probing the borders.)
This cannot be instantiated (D and String are classes, but one of them has to be mixed in. plus String is final.). But is there any other use for it?
class D {
foo: String =>
def f2 = foo.substring(1)
}
Update: Sorry, I seem to be not good at asking questions.
What I want to know is whether this strange special case makes sense. The case where class D can never be instantiated, as
1. I cannot mix in String, as it is not a tarit.
2. I cannot mix in D, as ..
3. I cannot extend String, as it is final.
The self type annotation generally has two purposes:
Enforce a certain base class/trait and ensure that your class or trait can only be inherited by or mixed into that type, and
Reference an exterior case when implementing an inner case. (If it wasn't for this syntax, what would 'this' refer to?)
I'm not sure I understand your example or the reasoning behind it. Elaborate?
trait Table
trait Desert
trait Meal
class Pancake extends Desert
class Spaghetti extends Meal
class Woodentable extends Table
suppose you want to make sure an existing Class mixes in those dependencies you use:
trait Restaurant {
self: Table with Desert with Meal =>
def foo():Unit ...
}
Now every class (or trait) that mixes in Restaurant has to provide the following dependencies. This is used in the cake pattern for instance. If any of these dependencies are not present the compiler will complain at compile time.

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.

Scala type parameters recurrence

In Scala you can define parameters that descend from other one that take the first one as parameter. For example in Lift you can find such things in Record and Mapper
MongoMetaRecord[BaseRecord <: MongoRecord[BaseRecord]]
What does it mean and how is that useful ?
This is a pattern often used to let an abstract class know about the type of the actual concrete class that extends it. It is sometimes useful to know what that final concrete type is — for instance, to use it as the return type of a method that produces a copy of the current object.
Suppose you want to do this — let an abstract class Abstract know about the concrete type implementing it. You could start by defining a type parameter, maybe like this:
trait Abstract[A] {
def copyObject: A = ...
}
But then you realize that actually, A should be a subclass of Abstract itself, as you don't want subclasses to provide a random parametrization. So you could add this:
trait Abstract[A <: Abstract]
... but you'll soon realize that Abstract has turned into a generic type as well, so you'll rather need this:
trait Abstract[A <: Abstract[A]]
As a final step, you'll probably want to make A covariant if you can, so as to allow intermediate abstract classes along the inheritance path from Abstract to the final concrete class:
trait Abstract[+A <: Abstract[A]]
class Concrete1 extends Abstract[Concrete1]
trait RefinedAbstract[+A <: RefinedAbstract[A]] extends Abstract[A]
class Concrete2 extends RefinedAbstract[Concrete2]
This means that every non-leaf (abstract) type should be parametrized, and that only the final concrete class will be able to drop the type parameter.