Suppose I have next traits:
trait A {
val a: String = "a"
}
trait B {
def a: String = "b"
}
And I want to mix both of these traits into some class C
class C extends B with A
Compiler doesn't allow me to create such class because I have to override method a
I want to override it using for example only A's implementaion. How can I do this?
EDIT
scala> class C extends B with A {
| override val a = super.a
| }
<console>:10: error: super may be not be used on value a
override val a = super.a
^
The compiler can't possibly know which one you intend to use, therefore you must specify it like:
class C extends B with A {
override def a = super[A].a
}
This approach allows you to choose the parent directly, regardless the trait order.
However, the traits define a differently (val and def) thus you must choose only one. You should use either def or val in both traits (not mix them).
Provided you make a a def in the A trait, you can do
class C extends B with A {
override val a = super.a
}
val c = new C
c.a // "a"
This will work because A is extended after B, so super will be its implementation.
Related
Assume the following situation
I have a trait A and a trait B that both declare a value that has the same name and type.
A defines the value explicitly, while B defines it implicitly
A and B are from external libraries and can not be changed. I don't want to fork.
I want to use both of them in a class C that is in my own code
How can I get them to align inside class C?
I want B.foo to be the value from A.foo
// External code, cant touch
trait A{
val foo = "boom"
}
trait B{
implicit val foo: String
}
// My class
class C extends A with B {
//uh oh??
}
Update (with help from Jasper-M)
// External code, cant touch
trait A{
val foo = "boom"
}
trait B{
implicit val foo: String
def implBang()(implicit s: String) = s
def doTheBang() = implBang()
}
// My class
class C extends B with A {}
new C().doTheBang; // Prints "boom"
Now only question remaining, how would I get foo to be in the implicit scope for class C?
Ideally you can select the implementation you want with super[Name]. But for vals that doesn't work for some reason.
class C extends A with B {
override implicit val foo = super[A].foo
// error: super may not be used on value foo
}
So if you really need some implicit String in C I would suggest just letting linearization do its thing and define another implicit val.
class C extends A with B {
implicit val bar = foo
}
You can just override the implicit variable, like:
// My class
class C extends A with B {
override implicit val foo = "My Value"
}
I understand how scala addresses the diamond inheritance situation by considering the order of the traits mentioned. I am curious to understand how it solves the same issue for fields. Here is what I am trying to understand -
class A {print("A")}
trait B extends A {print("B") ; val x="b"}
trait C extends B {print("C")}
trait D extends A {print("D"); val x="d"}
object TraitsEx extends App {
var d = new A with B with D
println(d.x)
}
The above code does not compile.
Well not magically as you can see. If this was a property of A class, then you could override it - with class linearization, you already know, each with X, where X extends A would override values:
trait A {
val x = "a"
}
trait B extends A {
override val x = "b"
}
trait C extends A {
override val x = "c"
}
object Main {
def main(args: Array[String]): Unit = {
println((new A {}).x)
println((new A with B).x)
println((new A with B with C).x)
}
}
prints
a
b
c
However, when each class introduces its own x that compiler cannot prove to override other xs, then it will leave solving that problem to you. It also suggest one solution:
object TraitsEx extends App {
var d = new A with B with D { override val x = "d" }
println(d.x)
}
this way you would override all different xs and remove ambiguity.
Scala solves conflicting fields by making you solve it.
Error:(21, 16) <$anon: A$A123.this.A with A$A123.this.B with A$A123.this.D> inherits conflicting members:
value x in trait B of type String and
value x in trait D of type String
(Note: this can be resolved by declaring an override in <$anon: A$A123.this.A with A$A123.this.B with A$A123.this.D>.)
var d = new A with B with D
^
If one field is supposed to override the other than you are required to put that in the code. Without a specified override the compiler won't make any decisions for you.
I have the following code in scala:
trait A {
val foo: String => Int = { in =>
in.toInt
}
}
trait B extends A {
def bar(a: String) = {
foo(a)
}
}
class C(a: String) {
self: B =>
val b = bar(a)
}
val x = new C("34") with B
During instantiation of x I get NPE. Couldn't figure out why.
edit
NOTE: Can not figure out why foo of A trait doesn't get initialized
Please refer to the http://docs.scala-lang.org/tutorials/FAQ/initialization-order.html.
The only addition to this is that self-type makes class C abstract. So actually you do:
abstract class C(a: String) {
def bar(a: String): Int
val b = bar(a)
}
val x = new C("34") with B
You can try to replace it in your code and see same result. Some more info here.
In short: the linearization of new C with B will be (B <- A) <- C, so initalization is C -> (A -> B). Please refer to Class Initialization section section:
After the superclass constructor is executed, the constructors for each mixin trait are executed. Since they are executed in right-to-left order within the linearization, but the linearization is created by reversing the order of the traits, this means the constructors for the mixin traits are executed in the order that they appear in the declaration for the class. Remember, however, that when mixins share hierarchy, the order of execution may not be quite the same as how the mixins appear in the declaration.
In your case new C("34") with B equals to class K extends C("34") with B; new K. Note that self type of class C doesn't affect the initialization order.
Simplified example:
scala> trait C {def aa: String; println(s"C:$aa")}
defined trait C
scala> trait D {val aa = "aa"; println(s"D:$aa")}
defined trait D
scala> new C with D
C:null
D:aa
res19: C with D = $anon$1#2b740b6
Solution: If your foo is placed in third party library (so you can't make it lazy), you may just use mix-in instead of self-type or at least mix A into the C class:
trait A {
val foo: String => Int = { in =>
in.toInt
}
}
trait B extends A {
def bar(a: String) = {
foo(a)
}
}
class C(a: String) extends A {
self: B =>
val b = bar(a)
}
val x = new C("34") with B
The short answer on why you get a NullPointerException is, that initialization of C requires initializing b, which invokes the method stored in val foo, which is not initialized at this point.
Question is, why is foo not initialized at this point? Unfortunately, I cannot fully answer this question, but I'd like to show you some experiments:
If you change the signature of C to extends B, then B, as the superclass of C is instantiated before, leading to no exception being thrown.
In fact
trait A {
val initA = {
println("initializing A")
}
}
trait B extends A {
val initB = {
println("initializing B")
}
}
class C(a: String) {
self: B => // I imagine this as C has-a B
val initC = {
println("initializing C")
}
}
object Main {
def main(args: Array[String]): Unit ={
val x = new C("34") with B
}
}
prints
initializing C
initializing A
initializing B
while
trait A {
val initA = {
println("initializing A")
}
}
trait B extends A {
val initB = {
println("initializing B")
}
}
class C(a: String) extends B { // C is-a B: The constructor of B is invoked before
val initC = {
println("initializing C")
}
}
object Main {
def main(args: Array[String]): Unit ={
val x = new C("34") with B
}
}
prints
initializing A
initializing B
initializing C
As you can see, the initialization order is different. I imagine the dependency-injection self: B => to be something like a dynamic import (i.e., putting the fields of an instance of B into the scope of C) with a composition of B (i.e., C has-a B). I cannot prove that it is solved like this, but when stepping through with IntelliJ's debugger, the fields of B are not listed under this while still being in the scope.
This should answer the question on why you get a NPE, but leaves the question open on why the mixin is not instantiated first. I cannot think of problems that may occur otherwise (since extending the trait does this basically), so this may very well be either a design choice, or noone thought about this use case. Fortunately, this will only yield problems during instantiation, so the best "solution" is probably to not use mixed-in values during instantiation (i.e., constructors and val/var members).
Edit: Using lazy val is also fine, so you can also define lazy val initC = {initB}, because lazy val are not executed until they are needed. However, if you do not care about side effects or performance, I would prefer def to lazy val, because there is less "magic" behind it.
Declare A.foo to be a lazy val.
I've tried to come up with a composition scenario in which self-type and extends behave differently and so far have not found one. The basic example always talks about a self-type not requiring the class/trait not having to be a sub-type of the dependent type, but even in that scenario, the behavior between self-type and extends seems to be identical.
trait Fooable { def X: String }
trait Bar1 { self: Fooable =>
def Y = X + "-bar"
}
trait Bar2 extends Fooable {
def Y = X + "-bar"
}
trait Foo extends Fooable {
def X = "foo"
}
val b1 = new Bar1 with Foo
val b2 = new Bar2 with Foo
Is there a scenario where some form of composition or functionality of composed object is different when using one vs. the other?
Update 1: Thanks for the examples of things that are not possible without self-typing, I appreciate the information, but I am really looking for compositions where self and extends are possible, but are not interchangeable.
Update 2: I suppose the particular question I have is why the various Cake Pattern examples generally talk about having to use self-type instead of extends. I've yet to find a Cake Pattern scenario that doesn't work just as well with extends
Cyclic references can be done with self-types but not with extends:
// Legal
trait A { self: B => }
trait B { self: A => }
// Illegal
trait C extends D
trait D extends C
I use this sometimes to split up implementations across multiple files, when there are cyclic dependencies.
Also,
scala> trait A { def a: String ; def s = "A" }
defined trait A
scala> trait B { _: A => def s = "B" + a }
defined trait B
scala> trait C extends A { def a = "c" ; override def s = "C" }
defined trait C
scala> new C {}.s
res0: String = C
scala> new A with B { def a = "ab" }.s
<console>:10: error: <$anon: A with B> inherits conflicting members:
method s in trait A of type => String and
method s in trait B of type => String
(Note: this can be resolved by declaring an override in <$anon: A with B>.)
new A with B { def a = "ab" }.s
^
scala> new A with B { def a = "ab" ; override def s = super[B].s }.s
res2: String = Bab
The point, if there is one, is that B.s doesn't override A.s.
That's not as motivational as the other answer.
The generic parameter must be the type itself:
trait Gen[T] {self : T => ...}
I don't see how you can get this constraint in say java or C#. It may however be approximated with
trait Gen[T] {
def asT : T // abstract
}
Also,
as for self type, it needs a trait to mix in. It cannot use class or object. The weird thing is it allows to define a class can mix in with class, but it only fails compilation when you try to instantiate it. see this question:
why self-type class can declare class
The biggest difference is in the public interface that you end up with. Let's take the example you give (slightly simplified):
trait Fooable { def foo: String = "foo" }
trait Bar1 { self: Fooable =>
def Y = foo + "-bar"
}
trait Bar2 extends Fooable {
def Y = foo + "-bar"
}
// If we let type inference do its thing we would also have foo() in the public interface of b1, but we can choose to hide it
def b1:Bar1 = new Bar1 with Fooable
// b2 will always have the type members from Bar2 and Fooable
def b2:Bar2 = new Bar2{}
// Doesn't compile - 'foo' definition is only visible inside the definition of Bar1
println(b1.foo)
// Compiles - 'foo' definition is visible outside the definition of Bar2
println(b2.foo)
So if you want to use the capabilities of a trait without necessarily letting your clients know that you are mixing the trait in, then you should use the self-type annotation.
Self-type annotation does not expose the public interface of the underlying type.
Extending another type always exposes the public interface of the parent type.
I was going through the effective scala slides and it mentions on slide 10 to never use val in a trait for abstract members and use def instead. The slide does not mention in detail why using abstract val in a trait is an anti-pattern. I would appreciate it if someone can explain best practice around using val vs def in a trait for abstract methods
A def can be implemented by either of a def, a val, a lazy val or an object. So it's the most abstract form of defining a member. Since traits are usually abstract interfaces, saying you want a val is saying how the implementation should do. If you ask for a val, an implementing class cannot use a def.
A val is needed only if you need a stable identifier, e.g. for a path-dependent type. That's something you usually don't need.
Compare:
trait Foo { def bar: Int }
object F1 extends Foo { def bar = util.Random.nextInt(33) } // ok
class F2(val bar: Int) extends Foo // ok
object F3 extends Foo {
lazy val bar = { // ok
Thread.sleep(5000) // really heavy number crunching
42
}
}
If you had
trait Foo { val bar: Int }
you wouldn't be able to define F1 or F3.
Ok, and to confuse you and answer #om-nom-nom—using abstract vals can cause initialisation problems:
trait Foo {
val bar: Int
val schoko = bar + bar
}
object Fail extends Foo {
val bar = 33
}
Fail.schoko // zero!!
This is an ugly problem which in my personal opinion should go away in future Scala versions by fixing it in the compiler, but yes, currently this is also a reason why one should not use abstract vals.
Edit (Jan 2016): You are allowed to override an abstract val declaration with a lazy val implementation, so that would also prevent the initialisation failure.
I prefer not use val in traits because the val declaration has unclear and non-intuitive order of initialization. You may add a trait to already working hierarchy and it would break all things that worked before, see my topic: why using plain val in non-final classes
You should keep all things about using this val declarations in mind which eventually road you to an error.
Update with more complicated example
But there are times when you could not avoid using val. As #0__ had mentioned sometimes you need a stable identifier and def is not one.
I would provide an example to show what he was talking about:
trait Holder {
type Inner
val init : Inner
}
class Access(val holder : Holder) {
val access : holder.Inner =
holder.init
}
trait Access2 {
def holder : Holder
def access : holder.Inner =
holder.init
}
This code produces the error:
StableIdentifier.scala:14: error: stable identifier required, but Access2.this.holder found.
def access : holder.Inner =
If you take a minute to think you would understand that compiler has a reason to complain. In the Access2.access case it could not derive return type by any means. def holder means that it could be implemented in broad way. It could return different holders for each call and that holders would incorporate different Inner types. But Java virtual machine expects the same type to be returned.
I agree with the other answers about avoiding abstract vals for the reason that it provides more options to implementations.
There are cases where you might need them:
For a path-dependent type (as mentioned by #0__).
Where implementations might be expensive and it is used in a concrete def.
(Are there others? If so please comment and I'll add them in).
The more important things to know is when it is safe to override something with a val and to have a lazy val that does not override something.
Rule 1: Never override a val or def with a non-lazy val unless it is a constructor parameter:
trait TraitWithVal {
// It makes no difference if this is concrete or abstract.
val a: String
val b: String = a
}
class OverrideValWithVal extends TraitWithVal {
// Bad: b will be null.
override val a: String = "a"
}
class OverrideValWithLazyVal extends TraitWithVal {
// Ok: b will be "a".
override lazy val a: String = "a"
}
// Ok: b will be "a".
class OverrideValWithConstructorVal(override val a: String = "a") extends TraitWithVal
//class OverrideValWithDef extends TraitWithVal {
// // Compilation error: method a needs to be a stable, immutable value.
// override def a: String = "a"
//}
println((new OverrideValWithVal).b) // null
println((new OverrideValWithLazyVal).b) // a
println((new OverrideValWithConstructorVal).b) // a
The same rule applies to a def:
trait TraitWithDef {
// It makes no difference if this is concrete or abstract.
def a: String
val b: String = a
}
class OverrideDefWithVal extends TraitWithDef {
// Bad: b will be null.
override val a: String = "a"
}
class OverrideDefWithLazyVal extends TraitWithDef {
// Ok: b will be "a".
override lazy val a: String = "a"
}
// Ok: b will be "a".
class OverrideDefWithConstructorVal(override val a: String = "a") extends TraitWithDef
class OverrideDefWithDef extends TraitWithDef {
// Ok: b will be "a".
override def a: String = "a"
}
println((new OverrideDefWithVal).b) // null
println((new OverrideDefWithLazyVal).b) // a
println((new OverrideDefWithConstructorVal).b) // a
println((new OverrideDefWithDef).b) // a
You might be wondering whether it would be ok to override a val with another val so long as it isn't used during initialisation. There is at least one edge cases which break this:
trait TraitWithValAndLazyVal {
val a: String = "A"
def b: String = a
}
class OverrideLazyValWithVal extends TraitWithValAndLazyVal {
// Bad: This on its own is ok but not if it is indirectly referenced during initialisation and overridden.
override val a = "a"
val c = b
}
class OverrideValWithVal extends OverrideLazyValWithVal {
override val a = "a"
}
println((new OverrideValWithVal).a) // a
println((new OverrideValWithVal).b) // a
println((new OverrideValWithVal).c) // null
Given that we already apply this rule to overriding defs then this makes using vals a little more acceptable in my opinion.
If you use a linter to enforce the override keyword and make sure your code never has any override val definitions then you are good.
You might be able to allow final override val but it's possible there are other edge cases that I haven't thought of.
Rule 2: Never use a lazy val that is not overriding another lazy val or def.
As far as I can tell there also is no good reason to have a lazy val that isn't overriding something. All the examples that I can come up with where it is needed, it is needed only because it violates Rule 1 and exposes the edge case I described earlier.
For example:
trait NormalLookingTrait {
def a: String
val b: String = a
}
trait TraitWithAbstractVal extends NormalLookingTrait {
val c: String
}
class OverrideValWithVal extends TraitWithAbstractVal {
override def a: String = c
override val c = "a"
}
println((new OverrideValWithVal).a) // a
println((new OverrideValWithVal).b) // null
println((new OverrideValWithVal).c) // a
So we make b a lazy val:
trait SuspiciousLookingTrait2 {
def a: String
lazy val b: String = a
}
trait TraitWithAbstractVal2 extends SuspiciousLookingTrait2 {
val c: String
}
class OverrideValWithVal2 extends TraitWithAbstractVal2 {
override def a: String = c
override val c = "a"
}
println((new OverrideValWithVal2).a) // a
println((new OverrideValWithVal2).b) // a
println((new OverrideValWithVal2).c) // a
Looks ok, except when we go one step further:
trait SuspiciousLookingTrait2 {
def a: String
lazy val b: String = a
}
trait TraitWithAbstractVal2 extends SuspiciousLookingTrait2 {
val c: String
}
class OverrideValWithVal2 extends TraitWithAbstractVal2 {
override def a: String = c
override val c = "a"
val d = b
}
class OverrideValWithVal3 extends OverrideValWithVal2 {
override val c = "a"
}
println((new OverrideValWithVal3).a) // a
println((new OverrideValWithVal3).b) // null
println((new OverrideValWithVal3).c) // a
println((new OverrideValWithVal3).d) // null
I now get what people mean when they say to only use lazy when it is absolutely necessary and never for delayed initialisation.
It's probably safe to break this rule if the trait / class is final but even that smells fishy.
Always using def seems a bit awkward since something like this won't work:
trait Entity { def id:Int}
object Table {
def create(e:Entity) = {e.id = 1 }
}
You will get the following error:
error: value id_= is not a member of Entity