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.
Related
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.
I am trying to understand the Mixins in the context of scala. In particular I wanted to know difference between concepts of inheritance and Mixins.
The definition of Mixin in wiki says :
A mixin class acts as the parent class, containing the desired functionality. A subclass can then inherit or simply reuse this functionality, but not as a means of specialization. Typically, the mixin will export the desired functionality to a child class, without creating a rigid, single "is a" relationship. Here lies the important difference between the concepts of mixins and inheritance, in that the child class can still inherit all the features of the parent class, but, the semantics about the child "being a kind of" the parent need not be necessarily applied.
In the above definition, I am not able to understand the statements marked in bold. what does it mean that
A subclass can inherit functionality in mixin but not as a means of specialization
In mixins, the child inherits all features of parent class but semantics about the child "being a kind" the parent need not be necessarily applied. - How can a child extend a parent and not necessarily a kind of Parent ? Is there an example like that.
I'm not sure I understood your question properly, but if I did, you're asking how something can inherit without really meaning the same thing as inheriting.
Mixins, however, aren't inheritance – it's actually more similar to dynamically adding a set of methods into an object. Whereas inheritance says "This thing is a kind of another thing", mixins say, "This object has some traits of this other thing." You can see this in the keyword used to declare mixins: trait.
To blatantly steal an example from the Scala homepage:
abstract class Spacecraft {
def engage(): Unit
}
trait CommandoBridge extends Spacecraft {
def engage(): Unit = {
for (_ <- 1 to 3)
speedUp()
}
def speedUp(): Unit
}
trait PulseEngine extends Spacecraft {
val maxPulse: Int
var currentPulse: Int = 0
def speedUp(): Unit = {
if (currentPulse < maxPulse)
currentPulse += 1
}
}
class StarCruiser extends Spacecraft
with CommandoBridge
with PulseEngine {
val maxPulse = 200
}
In this case, the StarCruiser isn't a CommandoBridge or PulseEngine; it has them, though, and gains the methods defined in those traits. It is a Spacecraft, as you can see because it inherits from that class.
It's worth mentioning that when a trait extends a class, if you want to make something with that trait, it has to extend that class. For example, if I had a class Dog, I couldn't have a Dog with PulseEngine unless Dog extended Spacecraft. In that way, it's not quite like adding methods; however, it's still similar.
A trait (which is called mixin when mixed with a class) is like an interface in Java (though there are many differences) where you can add additional features to a class without necessarily having "is a" relationship. Or you can say that generally traits bundle up features which can be used by multiple independent classes.
To give you an example from Scala library, Ordered[A] is a trait which provides implementation for some basic comparison operations (like <, <=, >, >=) to classes that can have data with natural ordering.
For example, let's say you have your own class Number and subclasses EvenNumber and OddNumber as shown below.
class Number(val num : Int) extends Ordered[Number] {
override def compare(that : Number) = this.num - that.num
}
trait Half extends Number {
def half() = num / 2
}
trait Increment extends Number {
def increment() = num + 1
}
class EvenNumber(val evenNum : Int) extends Number(evenNum) with Half
class OddNumber(val oddNum : Int) extends Number(oddNum) with Increment
In the example above, classes EvenNumber and OddNumber share is a relationship with Number but EvenNumber does not have "is a" relation with Half neither OddNumber share "is a" relation with Increment.
Another important point is even though class Number uses extends Ordered syntax, it means that Number has an implicit is a relationship with superclass of Ordered ie Any.
I think its very usage dependent. Scala being a multi-paradigm language makes it powerful as well as a bit confusing at times.
I think Mixins are very powerful when used the right way.
Mixins should be used to introduce behavior and reduce bolierplate.
A trait in Scala can have implementations and it is tempting to extend them and use them.
Traits could be used for inheritance. It can also be called mixins however that in my opinion is not the best way to use mixin behavior. In this case you could think of traits as Java Abstract Classes. Wherein you get subclasses that are "type of" the super class (the trait).
However Traits could be used as proper mixins as well. Now using a trait as a mixin depends on the implementation that is "how you mix it in". Mostly its a simple question to ask yourself . It is "Is the subclass of the trait truly a kind of the trait or are the behaviors in the trait behaviors that reduce boilerplate".
Typically it is best implemented by mixing in traits to objects rather than extending the trait to create new classes.
For example consider the following example:
//All future versions of DAO will extend this
trait AbstractDAO{
def getRecords:String
def updateRecords(records:String):Unit
}
//One concrete version
trait concreteDAO extends AbstractDAO{
override def getRecords={"Here are records"}
override def updateRecords(records:String){
println("Updated "+records)
}
}
//One concrete version
trait concreteDAO1 extends AbstractDAO{
override def getRecords={"Records returned from DAO2"}
override def updateRecords(records:String){
println("Updated via DAO2"+records)
}
}
//This trait just defines dependencies (in this case an instance of AbstractDAO) and defines operations based over that
trait service{
this:AbstractDAO =>
def updateRecordsViaDAO(record:String)={
updateRecords(record)
}
def getRecordsViaDAO={
getRecords
}
}
object DI extends App{
val wiredObject = new service with concreteDAO //injecting concrete DAO to the service and calling methods
wiredObject.updateRecords("RECORD1")
println(wiredObject.getRecords)
val wiredObject1 = new service with concreteDAO1
wiredObject1.updateRecords("RECORD2")
println(wiredObject1.getRecords)
}
concreteDAO is a trait which extends AbstractDAO - This is inheritance
val wiredObject = new service with concreteDAO -
This is proper mixin behavior
Since the service trait mandates the mixin of a AbstractDAO. It would be just wrong for Service to extend ConcreteDAO anyways because the service required AbstractDAO it is not a type of AbstractDAO.
Instead you create instances of service with different mixins.
The difference between mixin and inheritance is at semantic level. At syntax level they all are the same.
To mix in a trait, or to inherit from a trait, they all use extends or with which is the same syntax.
At semantic level, a trait that is intended to be mixed in usually doesn't have a is a relationship with the class mixining it which differs to a trait that is intended to be inherited.
To me, whether a trait is a mixin or parent is very subjective, which often time is a source of confusion.
I think it is talking about the actual class hierarchy. For example, a Dog is a type of Animal if it extends from the class (inheritance). It can be used wherever an Animal parameter is applicable.
I have a very specific scenario, in which I have some different abstract classes the have child case classes that can have different parameters, for example:
abstract class ball() {}
case class football(_name: String, _shape: String) extends ball
case class basketball(_name: String, _size: Int) extends ball
and a different abstract class:
abstract class food() {}
case class vegetarian(_name: String, calories: Int) extends food
case class meat(_name: String, proteinCount: Int) extends food
Now, the problem I'm facing is that I need to somehow extract the name of all of those without knowing what class it is, I just know that ALWAYS, EACH CLASS has a parameters named _name.
Supposing we have an object of any of above classes, I'm trying to do it like this:
object.getClass.getDeclaredField("_name").get(this)
But I'm getting the error:
can not access a member of class package.food with modifiers "private"
I tried putting val and var before parameters in class but it doesnt help. I also tried doing "setAccessible(true)" in a line before get(this), which also doesn't help.
The obvious clean solution would be to have a least a common trait to all these classes:
trait HasName {
def _name: String
}
and then you can safely do obj.asInstanceOf[HasName]._name. Better yet if you manage to keep around the static information that obj is a HasName, in which case obj._name suffices.
If you can't do any of that, reflection is the way to go. You can do it pretty easily using a structural type, in this case:
obj.asInstanceOf[{ def _name: String }]._name
Note that this will be slower than the above HasName solution, and completely unchecked at compile time.
In my specific case I have a (growing) library of case classes with a base trait (TKModel)
Then I have an abstract class (TKModelFactory[T <: TKModel]) which is extended by all companion objects.
So my companion objects all inherently know the type ('T') of "answers" they need to provide as well as the type of objects they "normally" accept for commonly implemented methods. (If I get lazy and cut and paste chunks of code to search and destroy this save my bacon a lot!) I do see warnings on the Internet at large however that any form of CompanionObject.method(caseClassInstance: CaseClass) is rife with "code smell" however. Not sure if they actually apply to Scala or not?
There does not however seem to be any way to declare anything in the abstract case class (TKModel) that would refer to (at runtime) the proper companion object for a particular instance of a case class. This results in my having to write (and edit) a few method calls that I want standard in each and every case class.
case class Track(id: Long, name: String, statusID: Long) extends TKModel
object Track extends TKModelFactory[Track]
How would I write something in TKModel such that new Track(1, "x", 1).someMethod() could actually call Track.objectMethod()
Yes I can write val CO = MyCompanionObject along with something like implicit val CO: ??? in the TKModel abstract class and make all the calls hang off of that value. Trying to find any incantation that makes the compiler happy for that however seems to be mission impossible. And since I can't declare that I can't reference it in any placeholder methods in the abstract class either.
Is there a more elegant way to simply get a reference to a case classes companion object?
My specific question, as the above has been asked before (but not yet answered it seems), is there a way to handle the inheritance of both the companion object and the case classes and find the reference such that I can code common method calls in the abstract class?
Or is there a completely different and better model?
If you change TKModel a bit, you can do
abstract class TKModel[T <: TKModel] {
...
def companion: TKModelFactory[T]
def someMethod() = companion.objectMethod()
}
case class Track(id: Long, name: String, statusID: Long) extends TKModel[Track] {
def companion = Track
}
object Track extends TKModelFactory[Track] {
def objectMethod() = ...
}
This way you do need to implement companion in each class. You can avoid this by implementing companion using reflection, something like (untested)
lazy val companion: TKModelFactory[T] = {
Class.forName(getClass.getName + "$").getField("MODULE$").
get(null).asInstanceOf[TKModelFactory[T]]
}
val is to avoid repeated reflection calls.
A companion object does not have access to the instance, but there is no reason the case class can't have a method that calls the companion object.
case class Data(value: Int) {
def add(data: Data) = Data.add(this,data)
}
object Data {
def add(d1: Data, d2: Data): Data = Data(d1.value + d2.value)
}
It's difficult. However you can create an implicit method in companion object. whenever you want to invoke your logic from instance, just trigger implicit rules and the implicit method will instantiate another class which will invoke whatever logic you desired.
I believe it's also possible to do this in generic ways.
You can implement this syntax as an extension method by defining an implicit class in the top-level abstract class that the companion objects extend:
abstract class TKModelFactory[T <: TKModel] {
def objectMethod(t: T)
implicit class Syntax(t: T) {
def someMethod() = objectMethod(t)
}
}
A call to new Track(1, "x", 1).someMethod() will then be equivalent to Track.objectMethod(new Track(1, "x", 1)).
(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.