0
scala> class A defined class A scala> trait T extends A { val t = 1 } defined trait T //why can I do this? scala> class B extends T defined class B scala> new B res0: B = B@2e9c76 scala> res0.t res1: Int = 1 

I thought that when you write trait T extends A, it makes it so you can only put trait T on a class that is a subclass of A. Why can I put it on B, then? Is this only for when you mix it in? Why is this not possible when declaring the class?

4 Answers 4

6

"it makes it so you can only put trait T on a class that is a subclass of A"

The feature you want is a self-type annotation. See also Daniel Sobral's answer to this question : What is the difference between self-types and trait subclasses? --> look for the links to dependancy-injection and cake-pattern.

trait A { def t: Int } trait B { this: A => // requires that a concrete implementation mixes in from A def t2: Int = t // ...and therefore we can safely access t from A } // strangely this doesn't work (why??) def test(b: B): Int = b.t // however this does def test2(b: B): Int = b.t2 // this doesn't work (as expected) class C extends B // and this conforms to the self-type class D extends B with A { def t = 1 } 
Sign up to request clarification or add additional context in comments.

Comments

1

What you can’t do is:

scala> class A2 defined class A2 scala> class B extends A2 with T <console>:8: error: illegal inheritance; superclass A2 is not a subclass of the superclass A of the mixin trait T class B extends A2 with T ^ 

Actually, writing class B extends T is the same as writing class B extends A with T.

Comments

0

You're simply confused about what a trait is. Saying class B extends T simply means that you're "mixing in" the functionality of the trait to the class definition of B. So, everything defined in T or it's parent classes and traits, is available in B.

3 Comments

Right, but trait T extends A is supposed to only allow you to mixin the trait to class A. It works as intended if you try doing new B with T - it won't let you.
No, trait T extends A is not supposed to only allow you to mixin the trait to class A. It is adding in the functionality of the class A to the trait T. So T has the functionality (methods and fields) of class A and anything you have defined in T. When you say class B extends T, you're bringing in everything from T and A.
@ThomasLockney You should take a look at stackoverflow.com/questions/12854941/… I think this is what reguy was referring to
0

You can specify the trait's subclass, though it will be redundant. Considering that this code

object TraitPulling { class A { val a = 0 println("I am constructor of A") } trait T extends A { val t = 1 } class B extends T class C extends A with T // though no T with A List(new T {}, new B(), new C()).foreach { e => println(s"t: ${e.t}, a: ${e.a}") } } TraitPulling 

gives the following output

I am constructor of A I am constructor of A I am constructor of A t: 1, a: 0 t: 1, a: 0 t: 1, a: 0 

we can deduce that since class A's content gets instantiated because it is implied (by trait T extends A), the three forms are semantically equivalent.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.