1

In following code, why does method A1 of traits C and D are called even though class B has defined A1?

scala> trait A {
     | def A1 = A2
     | def A2 //A2 is abstract and need implementation
     | }
defined trait A

scala> class B extends A {
     | def A2 = println("B") //implemented A2 in B
     | }
defined class B

scala> val b1 = new B
b1: B = B@163e8949

this works fine.

scala> b1.A1
B

scala> b1.A2
B

now I mix traits. C still has A2 abstract

scala> trait C extends A {
     | abstract override def A1 = {super.A1; C}
     | def C = println("C")
     | }
defined trait C

D still has A2 abstract strong text

scala> trait D extends A {
     | abstract override def A1 = {super.A1; D}
     | def D = println("D")
     | }
defined trait D

Why C and D are printed when I cam calling A1 of B. Shouldn't B's A1 only call B's A2 which is implemented to print B?

scala> val b2 = new B with C with D

b2: B with C with D = $anon$1@701d2b59

scala> b2.A1
B
C
D

scala> b2.A2
B

scala> val b3 = new B with D  with C
b3: B with D with C = $anon$1@270f28cf

scala> b3.A1
B
D
C
Manu Chadha
  • 15,555
  • 19
  • 91
  • 184
  • What do you want to achieve? Also look at how [trait linearizazion](https://stackoverflow.com/questions/34242536/linearization-order-in-scala) works in Scala. Examples work perfectly fine. – insan-e Oct 05 '17 at 08:32
  • want to understand how traits are called. I think I have got a hint now – Manu Chadha Oct 05 '17 at 08:36
  • A `def` in trait w/o type, `def` w/ same name (still no type) no `override` – cchantep Oct 05 '17 at 09:04

2 Answers2

0

I suppose what I am using is called stackable trait pattern. Basically, if I use new B with C with D and call a method, compiler will see if the method is defined in D, then C and then B (order is right to left). When the compiler sees an implementation it uses it. The use of super makes the compiler call the next implementation available in the class or trait on left (again right to left order)

Removed super calls.

scala> trait D extends A {
     | abstract override def A1 = { D}
     | def D = println("D")
     | }
defined trait D

scala> trait C extends A {
     | abstract override def A1 = {  C }
     | def C = println("C")
     | }
defined trait C

scala> val b3 = new B with D  with C
b3: B with D with C = $anon$1@7417ef4f

As super is removed, when compiler sees call to A1, it checks C first (rightmost, order is right to left) and it finds A1 and uses that implementation. As A1 no longer uses super, A1 in D or B are not called.

scala> b3.A1
C

If D is rightmost then only D's A1 is called

scala> val b3 = new B with C with D
b3: B with C with D = $anon$1@fd4459b

scala> b3.A1
D

Added super after print. This changes order or printing.

scala> trait C extends A {
     | abstract override def A1 = {  C ; super.A1}
     | def C = println("C")
     | }
defined trait C

scala> val b3 = new B with C with D
b3: B with C with D = $anon$1@4489f60f

scala> b3.A1
D

As super is called, after calling A1 from D, compiler looks for A1 of super class (next one on left) and keeps going towards left.

scala> val b3 = new B with D with C
b3: B with D with C = $anon$1@7b3c0ecb

scala> b3.A1
C
D

scala>
Manu Chadha
  • 15,555
  • 19
  • 91
  • 184
0

Why C and D are printed when I cam calling A1 of B. Shouldn't B's A1 only call B's A2 which is implemented to print B?

No. super.A1 refers to A#A1, which calls A2 of the object it's called on: not B#A2, not A#A2, but this.A2.

Also, C and D aren't related to B in any way, so they couldn't be calling B#A1 in any case: did you mean class C/D extends B?

Alexey Romanov
  • 167,066
  • 35
  • 309
  • 487