Mixing multiple traits in Scala - scala

Quick note: Examples from the tutorial Scala for Java Refugees Part 5: Traits and Types.
Suppose I have the traits Student, Worker, Underpaid, and Young.
How could I declare a class (not instance), CollegeStudent, with all these traits?
Note: I am aware of the simplests cases, such as CollegeStudent with one or two Traits:
class CollegeStudent extends Student with Worker

It is easy, when declaring a class you just use the "with" keyword as often as you want
class CollegeStudent extends Student with Worker with Underpaid with Young
the order of the traits can be important if a trait is changing the behavior of the class, it all depends on traits you are using.
Also if you don't want to have a class which always uses the same traits you can use them later:
class CollegeStudent extends Student
new CollegeStudent with Worker with Underpaid with NotSoYoungAnymore

I think that it is very important to explain not only the syntax, but also which role does the ordering of the traits play. I found the explanation in Jason Swartz's Learning Scala (page 177) quite enlightning.
A Scala class can extend multiple traits at once, but JVM classes can extend only one parent class. The Scala compiler solves this by creating "copies of each trait to form a tall, single-column hierarchy of the
class and traits", a process known as linearization.
In this context, extending multiple traits with identical field names would fail to compile, exactly the same "as if you were extending a class and providing your own version of a method but failed to add an override keyword".
And since it determines the shape of the inheritance tree, the linearization order is indeed one very important question to regard. As an example, class D extends A with B with C (where A is a class and B
and C are traits) would become class D extends C extends B extends A. The following few lines, also from the book, illustrate that perfectly:
trait Base { override def toString = "Base" }
class A extends Base { override def toString = "A->" + super.toString }
trait B extends Base { override def toString = "B->" + super.toString }
trait C extends Base { override def toString = "C->" + super.toString }
class D extends A with B with C { override def toString = "D->" + super.toString }
A call to new D() would have the REPL print the following:
D->C->B->A->Base
Which perfectly reflects the structure of the linearized inheritance graph.

Related

Define common copy for a class hierarchy with many case classes

I would like to define a class hierarchy with about 100 case classes deriving from common base. The types are describing nodes in the AST hierarchy, like this one. I would like to do something along the lines of:
trait Base {
def doCopy: Base
}
trait CloneSelf[T <: CloneSelf[T]] extends Base {
self: T =>
def copy(): T
override def doCopy: T = copy()
}
case class CaseA(a: String) extends Base with CloneSelf[CaseA]
case class CaseB(b: Int) extends Base with CloneSelf[CaseB]
This gives an error, because the existence of my copy prevents the case classes from defining the automatic copy. Is there some way how to implement the "clone" doCopy so that is uses the automatic copy of those case classes?
I would like to define a class hierarchy with about 100 case classes deriving from common base.
Please do not do that, you should absolutely find a pattern to avoid it! If you want to do this anyway... Try ducktyping:
trait CloneSelf[T <: {def copy(): T}] {
self: T =>
override def doCopy: T = copy()
}
I cannot test now so this probably won't compile, but you can figure it out by yourself with the general idea!
Edit:
Why having 100 subclasses is evil: imagine you perform one change in the base class, for instance change its name from Base to BaseCloning -> you'll have to change it in EVERY child class (100 changes).
How you will avoid that depends on what you want to do with your classes, check creationnal and structural patterns: factory, builder, prototype, flyweight, composite... Always think about "how much work will I have if I change something in the base class? Will it affect all children?"
I have found out defining the doCopy in each case class is actually less work than defining each class to inherit from CloneSelf. The code looks like this:
trait Base {
def doCopy: Base
}
case class CaseA(a: String) extends Base {
def doCopy = copy()
}
case class CaseB(b: Int) extends Base {
def doCopy = copy()
}
I was surprised to learn that without explicit type on the overridden method the type is inferred by the compiler, therefore the static type of CaseA("a").doCopy is the same as of CaseA("a").copy(), i.e. CaseA, not Base. Adding explicit type for each case class would be probably more obvious, but this would require more work compared to just copy-pasting the same line into each of them. Not that it matters much - when I do copying via the case class type, I may use the copy() as well. It is only when I have the Base I need the doCopy, therefore declaring it like def doCopy: Base = copy() would do little harm.

What is the difference between mixins and inheritance?

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.

Where would "abstract override" in subtrait with no implementation be useful, if any?

Given the following example of two traits with one extending another with no implementation of def a in each:
scala> trait A { def a: String }
defined trait A
scala> trait B extends A { abstract override def a: String }
defined trait B
Is the construct useful at all? What are the use cases?
I think the answer is essentially the same as the one linked in your comment. In Scala, the abstract keyword for methods isn't required, since the compiler can figure out whether it's abstract or not based on whether or not it has an implementation. So it's usage here is superfluous.
The override keyword is also not required for methods that are implementing an abstract method (or I guess not doing anything at all, in this case). So really, B is equivalent to:
trait B extends A { def a: String }
Or really just (since B will be assumed to be abstract):
trait B extends A
Similarly to the linked answer, I can imagine once scenario where using override might be useful for readability. If I were making the return type of a in B more specific than A, I could use override as a hint that I'm modifying the behavior in some way:
trait A {
def a: Any
}
trait B extends A {
override def a: String
}
In this case, I'm hinting that a in B might be slightly different than the inherited signature from A. Of course, this is only useful if it's known to the reader and used in a consistent manner. But I could still do the same thing without the override.
Short answer: abstract override is not useful in this case. It's basically like giving a type annotation where none would be needed.
The value added use of abstract override is for decorating an implementation that will be mixed in later, sometimes known as the "stackable trait pattern". See Why is "abstract override" required not "override" alone in subtrait?.
Abstract override indicates that you wish to override an 'abstract' method. Others address why it's useless here, so I'll focus on an example. Abstract override is best used for mixins. A simple example would be a Pollable trait:
trait Pollable{def poll:Double}
Lets say we want to weight this pollable. This trait will be a mixin for our trait. Our weighted pollable will have a weight field, which it will multiply a poll by to get a result. For example:
class OnePollable extends Pollable{
def poll:Double=1
}
val myWeightedOne=new OnePollable with WeightedPollable;
Lets try and write this trait:
//Does not compile
trait WeightedPollable extends Pollable{
var weight=1
def poll:Double=super.poll*weight
}
If you look, you'll see clearly why this doesn't work. Our trait tries to call a super type method that isn't implemented! One solution is to add a default to the super trait, Pollable:
//Don't do this!
trait Pollable{def poll:Double=1}
This sorta works here, but is sorta dumb in a lot of real world applications. The better way is this:
trait WeightedPollable extends Pollable{
var weight=1
abstract override def poll:Double=super.poll*weight
}
It's our friend the abstract override modifier! This tells the compiler that we are overriding an abstract method, but we want to use super to refer to an object we are being mixed into. This also disallows the trait being used as an interface.

Sealing a class which has many subtypes

I'm porting one of my C++ programs into Scala. In that project, there are hundreds of user-defined classes in an organised hierarchy. If I seal one of the top-level abstract classes, according to Scala rules, I have to put the definition of all subtypes of that class in the same file as the sealed class/trait. For one of my class hierarchies it would mean putting the definition of about 30 classes in that file.
In my C++ program these 30 classes are located in their own header and implementation files making them easier to maintain and read. I fear that if I put the definition of those 30 classes/objects in one file in my Scala application, it will make them hard to maintain and read.
The reason for sealing the class is so that I can do exhaustive searches when pattern matching on those types. Any help to point in me in the right direction with regards to organising Scala class hierarchies would be appreciated.
It's a bit of a pain to do this in separate classes, but it might be less painful than having everything in one huge file. First, you need to make sure you compile all the files together. Then, in your file where you make sure everything is sealed, you do the following:
trait GenericA { def foo: Int }
sealed trait A extends GenericA
case class B() extends A with ImplB {}
case class C() extends A with ImplC {}
...
The trick is that everything in the superclass (and it can be an abstract class instead of a trait if you wish) goes into GenericA. But you never actually use GenericA in your code, you just use A. Now, you can write a bunch of separate files with each implementation, defined like so:
// File #1
trait ImplB extends GenericA { def foo = 7 }
// File #2
trait ImplC extends GenericA { def foo = 4 }
...
Now you have your implementations separated out (at least those parts which can be expressed in terms of GenericA only).
What if you need the case class parameters available also? No problem--just include those as part of the trait.
// Main file
case class D(i: Int) extends A with ImplD {}
// Separate file
trait ImplD {
def i: Int
def foo = i*3
}
It's a bit of extra work since you have to repeat the case class parameters in two spots, but in your case it may be worth it.
Assuming your classes are case-classes which have many methods (which could make your file grow), you can try to separate definition from implementation using type classes (but sometimes it could afffect compiler's performance), like:
Model.scala
sealed trait A
case class A1(a: Int) extends A
case class A2(a: Int) extends A
case class A3(a: Int, b: Int) extends A
...
case class A1(a: Int) extends A
ImplA1.scala
package org.impl
implicit class ImplA1(a: A1) {
def method1() = a.a + a.a
}
ImplA2.scala
package org.impl
implicit class ImplA2(a: A2) {
def method1() = a.a * 2
}
Usage:
import org.impl._
val a1 = new A1
a1.method1()

Seamless weaving of trait

I would like to automatically weave the definition of a new function say introduced by an extending trait Ext into an abstract class A:
class Base {
abstract class A
class B extends A
case class C extends A
}
trait Ext extends Base {
trait A extends super.A {
def say = "hello"
}
}
object Test extends Base with Ext {
val b = new B
b.say
}
However, I obtain the following error:
<console>:12: error: value say is not a member of Test.B
b.say
Any way of doing it?
It seems you are trying to use virtual classes, which is a feature not available in Scala.
Once A and B are defined they can't be redefined (like method overriding).
abstract class A
class B extends A
On the other hand, given your example, your objective could be achieved by a simple mixin. Here it is with few rewrites:
class Base {
abstract class A
class B extends A
case class C extends A
}
trait Ext extends Base {
trait CanSay extends A {
def say = "hello"
}
}
object Test extends Base with Ext {
val b = new B with CanSay
def apply = b.say
}
Test.apply
No sure it will really help, but at least will help you understand what is going on.
Okay, as I said in a comment, it's not entirely clear what you're trying to do here, so I can't really try to suggest ways to do it. However, the approach you're using at the moment will not work.
Consider the class Hierarchy in this situation. At the base, we have A, which is then subclassed with B (in Base) and with Ext.A. These are not related save by their shared supertype, so you'll never find a say method on an instance of B.
The confusion possibly arises through the use of the word abstract. An abstract modifier on a class (even an inner class) does not make it an abstract member of the parent class, but denotes that it itself may have abstract members. There are ways of giving a class an abstract class member - through type parameters or type members. Unfortunately, you cannot derive from these AFAIK.