I am confused. In my existing project, I am not able to find the difference between extends
and with
. Could you please help me?
The first thing you inherit from can either be a trait or a class, using the extends
keyword.
trait SomeTrait
class SomeClass
class ThisIsValid extends SomeTrait
class ThisAsWell extends SomeClass
You can define further inherited traits (and only traits) using the with
keyword.
class AlsoThisWorks extends SomeClass with SomeTrait
If a trait inherits from a class you cannot use it like in the above example.
That's it regarding the extends
and with
keywords. If you want to learn more about classes and traits the official documentation goes in depth on the topic.
If you have multiple class
es or trait
s to inherit, the first one is always extends
, and the following >=0 class
/trait
to be with
s.
But remember that you can only inherit <=1 (abstract) class, which means if you need to inherit a parent class (Parent
), it should always comes at first of the form ... extends Parent ...
, and no more classes can be inherited to the derived class.
trait T1
trait T2
class P1
class P2
class C1 extends T1
class C2 extends T1 with T2
class C3 extends T2 with T1
class C4 extends P1 with T1
/// class C5 extends T1 with P1 // invalid
/// class C6 extends P1 with P2 // invalid
with
is in fact bound to the class/trait that is extend
ed, e.g., class C7 extends P1 with T1 with T2
reads class C7 extends (P1 with T1 with T2)
.
Note that this is only from the viewpoint of syntax, the semantic differences can be referred from the followings:
trait
and (abstract
) class
is
here;In Scala, you can inherit from class
es (concrete or abstract
) and trait
s. In a similar way to how you can extend only one class, but implement as many interfaces as you'd like in Java, you're only allowed to inherit from one class
, but as many trait
s as you'd like.
If you are extending a class
, that class should immediately follow the extends
keyword. Any trait
s you are extending from should follow, separated by with
keywords.
If you are not extending a class, you can put your first trait
right after the extends
keyword and continue after that.
Just as in Java, every class is a subclass of Object
whether you explicitly declare it or not, every (user-defined) class in Scala extends AnyRef with ScalaObject
whether or not you include that explicitly.
The following sets of declarations are therefore equivalent:
class MyClass { ... }
class MyClass extends AnyRef with ScalaObject { ... }
class MyClass extends MySuperClass { ... }
class MyClass extends MySuperClass with ScalaObject { ... }
class MyClass extends MyTrait1 with MyTrait2 { ... }
class MyClass extends AnyRef with MyTrait1 with MyTrait2 { ... }
class MyClass extends MySuperClass with MyTrait1 with MyTrait2 { ... }
The last example is not the same if you change the order of MySuperClass
, MyTrait1
, and MyTrait2
. In particular, you cannot put a trait in front of a class and the order in which you stack traits is important if they both have implementations for the same methods. (In that case, the last one "wins".)
Remember also that only class
es in Scala can have parameters, so you'll only ever be able to attach parameters to the type after the extends
keyword, never to any of the types listed after with
.
Hope that helps!