I want to understand the difference between these 2 codes.
Lets look at the following 2 pieces of code in Scala.
trait Expressions {
// Bunch of functions
}
CODE 1:
trait Scheduling{
val IR : Expressions
import IR._
// Bunch of functions
}
CODE 2:
trait Scheduling extends Expressions {
// Same Bunch of functions
}
What is the difference between those 2 codes?
Thanks
Your first code snippet requires that any class that extends the trait has a variable named IR of type Expressions. All members of that variable are then imported so they can be used within your "bunch of functions".
The Expression instance is aggregated.
In your second example you're inheriting the trait. This requires that the class that implements your trait must also implement the Expressions trait.
Both example result in the same semantic: A implementation of all members of the Expressions trait is available to your "Bunch of methods".
The only difference is that aggregation is bit more flexible since you can use any object that implements the Expressions.
Your second example can be seen as equivalent to the first one if your trait implementation definesval IR = this.
Here are some of the key differences between the two versions of Scheduling:
Objects that inherit from Scheduling in CODE1...
Must provide a val IR of type Expressions
Have an extra member IR that is visible from outside the object
May use a sub-class of Expressions with different implementations of the methods in Expressions
Can access all the methods of Expressions as IR.<method>
Objects that inherit from Scheduling in CODE2..
Have the type Expressions
Can access all the methods of Expressions directly
Related
What is the advantage of using an abstract class instead of a trait (apart from performance)? It seems like abstract classes can be replaced by traits in most cases.
I can think of two differences
Abstract classes can have constructor parameters as well as type parameters. Traits can have only type parameters. There was some discussion that in future even traits can have constructor parameters
Abstract classes are fully interoperable with Java. You can call them from Java code without any wrappers. Traits are fully interoperable only if they do not contain any implementation code
There's a section in Programming in Scala called "To trait, or not to trait?" which addresses this question. Since the 1st ed is available online, I'm hoping it's OK to quote the whole thing here. (Any serious Scala programmer should buy the book):
Whenever you implement a reusable collection of behavior, you will
have to decide whether you want to use a trait or an abstract class.
There is no firm rule, but this section contains a few guidelines to
consider.
If the behavior will not be reused, then make it a concrete class. It
is not reusable behavior after all.
If it might be reused in multiple, unrelated classes, make it a trait.
Only traits can be mixed into different parts of the class hierarchy.
If you want to inherit from it in Java code, use an abstract class.
Since traits with code do not have a close Java analog, it tends to be
awkward to inherit from a trait in a Java class. Inheriting from a
Scala class, meanwhile, is exactly like inheriting from a Java class.
As one exception, a Scala trait with only abstract members translates
directly to a Java interface, so you should feel free to define such
traits even if you expect Java code to inherit from it. See Chapter 29
for more information on working with Java and Scala together.
If you plan to distribute it in compiled form, and you expect outside
groups to write classes inheriting from it, you might lean towards
using an abstract class. The issue is that when a trait gains or loses
a member, any classes that inherit from it must be recompiled, even if
they have not changed. If outside clients will only call into the
behavior, instead of inheriting from it, then using a trait is fine.
If efficiency is very important, lean towards using a class. Most Java
runtimes make a virtual method invocation of a class member a faster
operation than an interface method invocation. Traits get compiled to
interfaces and therefore may pay a slight performance overhead.
However, you should make this choice only if you know that the trait
in question constitutes a performance bottleneck and have evidence
that using a class instead actually solves the problem.
If you still do not know, after considering the above, then start by
making it as a trait. You can always change it later, and in general
using a trait keeps more options open.
As #Mushtaq Ahmed mentioned, a trait cannot have any parameters passed to the primary constructor of a class.
Another difference is the treatment of super.
The other difference between classes and traits is that whereas in classes, super calls are statically bound, in traits, they are dynamically bound. If you write super.toString in a class, you know exactly which method implementation will be invoked. When you write the same thing in a trait, however, the method implementation to invoke for the super call is undefined when you define the trait.
See the rest of Chapter 12 for more details.
Edit 1 (2013):
There is a subtle difference in the way abstract classes behaves compared to traits. One of the linearization rules is that it preserves the inheritance hierarchy of the classes, which tends to push abstract classes later in the chain while traits can happily be mixed in. In certain circumstances, it's actually preferable to be in latter position of the class linearization, so abstract classes could be used for that. See constraining class linearization (mixin order) in Scala.
Edit 2 (2018):
As of Scala 2.12, trait's binary compatibility behavior has changed. Prior to 2.12, adding or removing a member to the trait required recompilation of all classes that inherit the trait, even if the classes have not changed. This is due to the way traits were encoded in JVM.
As of Scala 2.12, traits compile to Java interfaces, so the requirement has relaxed a bit. If the trait does any of the following, its subclasses still require recompilation:
defining fields (val or var, but a constant is ok – final val without result type)
calling super
initializer statements in the body
extending a class
relying on linearization to find implementations in the right supertrait
But if the trait does not, you can now update it without breaking binary compatibility.
For whatever it is worth, Odersky et al's Programming in Scala recommends that, when you doubt, you use traits. You can always change them into abstract classes later on if needed.
Other than the fact that you cannot directly extend multiple abstract classes, but you can mixin multiple traits into a class, it's worth mentioning that traits are stackable, since super calls in a trait are dynamically bound (it is referring a class or trait mixed before current one).
From Thomas's answer in Difference between Abstract Class and Trait:
trait A{
def a = 1
}
trait X extends A{
override def a = {
println("X")
super.a
}
}
trait Y extends A{
override def a = {
println("Y")
super.a
}
}
scala> val xy = new AnyRef with X with Y
xy: java.lang.Object with X with Y = $anon$1#6e9b6a
scala> xy.a
Y
X
res0: Int = 1
scala> val yx = new AnyRef with Y with X
yx: java.lang.Object with Y with X = $anon$1#188c838
scala> yx.a
X
Y
res1: Int = 1
When extending an abstract class, this shows that the subclass is of a similar kind. This is not neccessarily the case when using traits, I think.
In Programming Scala the authors say that abstract classes make a classical object oriented "is-a" relationship while traits are a scala-way of composition.
Abstract classes can contain behaviour - They can parameterized with constructor args (which traits can't) and represent a working entity. Traits instead just represent a single feature, an interface of one functionality.
A class can inherit from multiple traits but only one abstract class.
Abstract classes can have constructor parameters as well as type parameters. Traits can have only type parameters. For example, you can’t say trait t(i: Int) { }; the i parameter is illegal.
Abstract classes are fully interoperable with Java. You can call them from Java code without any wrappers. Traits are fully interoperable only if they do not contain any implementation code.
I am wondering if there is a way to get the quick documentation in IntelliJ to work for the class construction pattern many scala developers use below.
SomeClass(Param1,Parma2)
instead of
new SomeClass(param1,Param2)
The direct constructor call made with new obviously works but many scala devs use apply to construct objects. When that pattern is used the Intelij documentation look up fails to find any information on the class.
I don't know if there are documents in IntelliJ per se. However, the pattern is fairly easy to explain.
There's a pattern in Java code for having static factory methods (this is a specialization of the Gang of Four Factory Method Pattern), often along the lines of (translated to Scala-ish):
object Foo {
def barInstance(args...): Bar = ???
}
The main benefit of doing this is that the factory controls object instantiation, in particular:
the particular runtime class to instantiate, possibly based on the arguments to the factory. For example, the generic immutable collections in Scala have factory methods which may create optimized small collections if they're created with a sufficiently small amount of contents. An example of this is a sequence of length 1 can be implemented with basically no overhead with a single field referring to the object and a lookup that checks if the offset is 0 and either throws or returns its sole field.
whether an instance is created. One can cache arguments to the factory and memoize or "hashcons" the created objects, or precreate the most common instances and hand them out repeatedly.
A further benefit is that the factory is a function, while new is an operator, which allows the factory to be passed around:
class Foo(x: Int)
object Foo {
def instance(x: Int) = new Foo(x)
}
Seq(1, 2, 3).map(x => Foo(x)) // results in Seq(Foo(1), Foo(2), Foo(3))
In Scala, this is combined with the fact that the language allows any object which defines an apply method to be used syntactically as a function (even if it doesn't extend Function, which would allow the object to be passed around as if it's a function) and with the "companion object" to a class (which incorporates the things that in Java would be static in the class) to get something like:
class Foo(constructor_args...)
object Foo {
def apply(args...): Foo = ???
}
Which can be used like:
Foo(...)
For a case class, the Scala compiler automatically generates a companion object with certain behaviors, one of which is an apply with the same arguments as the constructor (other behaviors include contract-obeying hashCode and equals as well as an unapply method to allow for pattern matching).
Imagine this:
val myObject = if(someCondition) {
new Whatever with Trait1
} else if(otherCondition) {
new Whatever with Trait2 with Trait3 with Trait4
} else {
new Whatever with Trait5
}
Is the myObject object "composed" at runtime, or is the scala compiler smart enough to generate the appropriate code at compile time? What kind of performance impact will it have on the code if you have multiple places that are applying traits like in the above code?
It's composed at compile-time
The traits will be added as interfaces to the resulting type, and any concrete methods from those traits will (usually) be copied to the class in their entirety.
Occasionally, the compiler may have to provide concrete implementations via forwarders to static methods, but this isn't usually the case.
Scala will create three anonymous classes, (except the last condition is a syntax error).
Note: These classes will be named using the order in which they are defined in the scope they are defined. So... OuterClass$anon$1 -> 3. Please avoid using these anonymous classes in any long-term Java-serialization as this locks down the order of anonymous classes in your code.
Other than that, it's an awesome convenience feature!
What's the best way of grouping utility functions that don't belong in a class? In Ruby, I would have grouped them in a module. Should I use traits in Scala for the same effect, or objects?
Usually, I put utility functions that are semantically different into different traits and create an object for each trait, e.g.
trait Foo {
def bar = 1
}
object Foo extends Foo
That way I'm most flexible. I can import the utility functions via an import statement or via with in the class declaration. Moreover I can easily group different utility traits together into a new object to simplify the import statements for the most commonly used utility functions, e.g.
object AllMyUtilites extends Foo with Foo2
Package objects or just plain objects.
See, for instance, Scala.Predef and scala.math.
Traits if you want them to be mixed in with the classes that are going to use it. Objects if you want to only have to import them.
What is the advantage of using an abstract class instead of a trait (apart from performance)? It seems like abstract classes can be replaced by traits in most cases.
I can think of two differences
Abstract classes can have constructor parameters as well as type parameters. Traits can have only type parameters. There was some discussion that in future even traits can have constructor parameters
Abstract classes are fully interoperable with Java. You can call them from Java code without any wrappers. Traits are fully interoperable only if they do not contain any implementation code
There's a section in Programming in Scala called "To trait, or not to trait?" which addresses this question. Since the 1st ed is available online, I'm hoping it's OK to quote the whole thing here. (Any serious Scala programmer should buy the book):
Whenever you implement a reusable collection of behavior, you will
have to decide whether you want to use a trait or an abstract class.
There is no firm rule, but this section contains a few guidelines to
consider.
If the behavior will not be reused, then make it a concrete class. It
is not reusable behavior after all.
If it might be reused in multiple, unrelated classes, make it a trait.
Only traits can be mixed into different parts of the class hierarchy.
If you want to inherit from it in Java code, use an abstract class.
Since traits with code do not have a close Java analog, it tends to be
awkward to inherit from a trait in a Java class. Inheriting from a
Scala class, meanwhile, is exactly like inheriting from a Java class.
As one exception, a Scala trait with only abstract members translates
directly to a Java interface, so you should feel free to define such
traits even if you expect Java code to inherit from it. See Chapter 29
for more information on working with Java and Scala together.
If you plan to distribute it in compiled form, and you expect outside
groups to write classes inheriting from it, you might lean towards
using an abstract class. The issue is that when a trait gains or loses
a member, any classes that inherit from it must be recompiled, even if
they have not changed. If outside clients will only call into the
behavior, instead of inheriting from it, then using a trait is fine.
If efficiency is very important, lean towards using a class. Most Java
runtimes make a virtual method invocation of a class member a faster
operation than an interface method invocation. Traits get compiled to
interfaces and therefore may pay a slight performance overhead.
However, you should make this choice only if you know that the trait
in question constitutes a performance bottleneck and have evidence
that using a class instead actually solves the problem.
If you still do not know, after considering the above, then start by
making it as a trait. You can always change it later, and in general
using a trait keeps more options open.
As #Mushtaq Ahmed mentioned, a trait cannot have any parameters passed to the primary constructor of a class.
Another difference is the treatment of super.
The other difference between classes and traits is that whereas in classes, super calls are statically bound, in traits, they are dynamically bound. If you write super.toString in a class, you know exactly which method implementation will be invoked. When you write the same thing in a trait, however, the method implementation to invoke for the super call is undefined when you define the trait.
See the rest of Chapter 12 for more details.
Edit 1 (2013):
There is a subtle difference in the way abstract classes behaves compared to traits. One of the linearization rules is that it preserves the inheritance hierarchy of the classes, which tends to push abstract classes later in the chain while traits can happily be mixed in. In certain circumstances, it's actually preferable to be in latter position of the class linearization, so abstract classes could be used for that. See constraining class linearization (mixin order) in Scala.
Edit 2 (2018):
As of Scala 2.12, trait's binary compatibility behavior has changed. Prior to 2.12, adding or removing a member to the trait required recompilation of all classes that inherit the trait, even if the classes have not changed. This is due to the way traits were encoded in JVM.
As of Scala 2.12, traits compile to Java interfaces, so the requirement has relaxed a bit. If the trait does any of the following, its subclasses still require recompilation:
defining fields (val or var, but a constant is ok – final val without result type)
calling super
initializer statements in the body
extending a class
relying on linearization to find implementations in the right supertrait
But if the trait does not, you can now update it without breaking binary compatibility.
For whatever it is worth, Odersky et al's Programming in Scala recommends that, when you doubt, you use traits. You can always change them into abstract classes later on if needed.
Other than the fact that you cannot directly extend multiple abstract classes, but you can mixin multiple traits into a class, it's worth mentioning that traits are stackable, since super calls in a trait are dynamically bound (it is referring a class or trait mixed before current one).
From Thomas's answer in Difference between Abstract Class and Trait:
trait A{
def a = 1
}
trait X extends A{
override def a = {
println("X")
super.a
}
}
trait Y extends A{
override def a = {
println("Y")
super.a
}
}
scala> val xy = new AnyRef with X with Y
xy: java.lang.Object with X with Y = $anon$1#6e9b6a
scala> xy.a
Y
X
res0: Int = 1
scala> val yx = new AnyRef with Y with X
yx: java.lang.Object with Y with X = $anon$1#188c838
scala> yx.a
X
Y
res1: Int = 1
When extending an abstract class, this shows that the subclass is of a similar kind. This is not neccessarily the case when using traits, I think.
In Programming Scala the authors say that abstract classes make a classical object oriented "is-a" relationship while traits are a scala-way of composition.
Abstract classes can contain behaviour - They can parameterized with constructor args (which traits can't) and represent a working entity. Traits instead just represent a single feature, an interface of one functionality.
A class can inherit from multiple traits but only one abstract class.
Abstract classes can have constructor parameters as well as type parameters. Traits can have only type parameters. For example, you can’t say trait t(i: Int) { }; the i parameter is illegal.
Abstract classes are fully interoperable with Java. You can call them from Java code without any wrappers. Traits are fully interoperable only if they do not contain any implementation code.