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.
Related
I need overriding implicit in object res defing one from trait. The purpose is to define custom implicits in one place (trait B). Trait a is defined in external library. Is it possible?
trait t {
}
object m extends t
object q extends t
trait a {
implicit val o: t = m
}
trait b {
implicit val o: t = q
}
trait c {
def action(implicit v: t): Unit = {}
}
object res extends c with a with b {
//i need smth like override val o = super[b].o
val ololo= action
}
It is not possible to mix-in two unrelated traits that both contain a member with the same identifier. The Scala compiler has no way to resolve which one would take precedence in this scenario. Since types A and B are related, o does not even need to have the same type in both of them. Trait B needs to extend A and override o. There isn't any other way to override a member without using inheritance.
trait T
case object M extends T
case object Q extends T
trait A {
implicit val o: T = M
}
trait B extends A {
override implicit val o: T = Q
}
trait C {
def action(implicit v: T): Unit = println(v)
}
object Res extends C with B {
def call() = action
}
scala> Res.call()
Q
Since you are already mixing A into Res anyway, it is assumed that A is not difficult to extend, since Res must implement any other unmentioned abstract members.
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.
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.
object P{
object P1{
class A{
//I want only classes/objects that extends A AND in the package P1 can access x
//It means, the modifier `protected` and the qualifier [P1] is combined with operator `AND`:
//protected AND [P1] means, x is:
// protected: not in subclass then not accessible
// AND [P1]: not in [P1] then not accessible
//protected OR [P1] means, x is:
// protected: not in subclass then not accessible
// OR [P1]: not in [P1] then not accessible
protected[P1] val x = 1
//Like `protected[this]`: y is protected AND [this]
//because y is accessible only in subclass AND in the same object
//(access to y in B2.f2 is permit but in B2.f3 is deny)
//(if protected[this] == protected OR [this] then protected[this] == protected :D)
protected[this] val y = 2
//Also, I don't know why the following code is valid
//(scalac 2.10.0 compile it!). Is this an error in scala compiler?
//But this strange modifiers combination is also not what I want!
private[P1] protected val z = 1
}
class B{
def f(a: A) = a.x + a.z //permit!
}
}
object P2{
class B2 extends P1.A{
def f = x + z //also permit!
def f2 = y //permit. OK
def f3(b: B2) = b.y //deny. OK
}
}
}
I know that protected[P1] modifier on x is same as java's protected. But, how to allow access to A.x only from classes/objects that extends A AND in the package P1?
EDIT:
#Randal ask: "Why do you care about the package constraint? What does that get you?"
I have a large project with a complex class. I split the class to several trait. But some members in some traits is intend to be used only in some (but not all) other sub-traits. So, I organize all traits that need the accessibility in one package. And the instantable class that need logic of those traits is put in another package. But the class need access to only some traits' members. Then I want only the needed members is visible to the class:
package p.base
private[base] trait A{
//x is intent to be used only in trait B and C
protected[base] val x = 1
}
private[base] trait B{this: A =>
//f is intent to be used only in trait C
protected[base] def f = x
//f2 will be used in global.D
def f2 = f
}
private[p] trait C extends B with A{...}
package p.global
class D extends p.base.C{
def g = f2
}
It's not possible using specialized access modifiers only. To get the compile time restrictions you could use a technique like this
object P {
object P1 {
class A {
#implicitNotFound(msg = "Only accessible when extending from A")
sealed trait OnlyA
protected[this] implicit object OnlyA extends OnlyA
private[P1] def x(implicit ev: A#OnlyA) = 1
private[P1] val z = 1
}
class B {
def f(a: A) = a.z + a.x // Will not work
}
class C extends A {
def f(a: A) = a.z + a.x // Works
}
}
object P2 {
class B2 extends P1.A {
def f = x // Will not work
def f(a: P1.A) = a.x + a.z // Will not work
}
}
}
You can protect the constructor with private[PkgName] and supply a factory to provide public creation so subclassing is confined to that package:
package pkg
...
class A private[pkg] { ...
}
object A {
def apply(): A = new A
}
...