0
trait A { def someMethod = 1}
trait B { self : A => }

val refOfTypeB : B = new B with A

refOfTypeB.someMethod

The last line results in a type mismatch error. My question is: why it's impossible to reach the method (of A) when it's given that B is also of type A?

Lukasz Gieron
  • 276
  • 2
  • 12

2 Answers2

2

So B is not also of type A. The self type annotation that you've used here indicates specifically that B does not extend A but that instead, wherever B is mixed in, A must be mixed in at some point as well. Since you downcast refOfTypeB to a B instead of B with A you don't get access to any of type A's methods. Inside of the implementation of the B trait you can access A's methods since the compiler knows that you'll at some point have access to A in any implemented class. It might be easier to think about it as B depends on A instead of B is an A.

For a more thorough explanation see this answer: What is the difference between self-types and trait subclasses?

Community
  • 1
  • 1
Noah
  • 13,821
  • 4
  • 36
  • 45
  • Yeah I get that it's how it works now, I'm just disappointed that they didn't decide to make outside references (like in my example) work as well. Since the compiler knows that B will always have all properties of type A, they could have made them accessible from outside (unless I'm missing something?) – Lukasz Gieron Nov 21 '13 at 21:04
  • Think of this as dependency injection. If you inject a database connection as a dependency to `B` you wouldn't expect `B` to also have all methods of your database connection publicly available? If you want these methods public why not just use `trait B extends A` instead of self types? – Noah Nov 21 '13 at 21:50
  • Unfortunately I can't do it because in my case A is a class. – Lukasz Gieron Nov 22 '13 at 00:20
  • Actually, your last comment led me to reevaluate the need for the classes (all of them abstract) and it turns out that whatever I wanted to achieve with abstract classes, I can do with traits (and in more conscise way!). I wonder if abstract classes are in Scala just for Java interoperability. – Lukasz Gieron Nov 22 '13 at 00:34
0

The problem is when you declare refOfTypeB, you have type B specified but not type B with A.

The self => syntax allow you to access the properties of A within B and pass the compilation.

However, in the runtime, refOfTypeB is not recognize as B with A and the compiler doesn't necessarily have the function map correctly.

So, the correct syntax should be:

trait A { def someMethod = 1}
trait B { self : A => }

val refOfTypeB : B with A = new B with A

refOfTypeB.someMethod //1

Indeed, this is more expressive in terms of explaining with what refOfTypeB exactly is.

This is the somehow the boilerplate of cake patterns.

Joyfulvillage
  • 547
  • 1
  • 4
  • 13