Scala - extends vs with - scala

I am confused. In my existing project, I am not able to find the difference between extends and with. Could you please help me?

If you have multiple classes or traits to inherit, the first one is always extends, and the following >=0 class/trait to be withs.
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 extended, 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:
use of trait and (abstract) class is
here;
The resolution rule is the so-called
class linearization; there is a post about it.

In Scala, you can inherit from classes (concrete or abstract) and traits. 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 traits as you'd like.
If you are extending a class, that class should immediately follow the extends keyword. Any traits 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 classes 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!

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.

Related

Is it possible to mix in trait in abstract class but make it specific to each subclass in Scala?

I wrote some code for Logic Expressions in Scala and I was wondering if I could find a way to mix in a trait into an abstract class, so I don't have to extend it in every subclass. Here is what I've got:
abstract class LogicExpression
case class Literal(lit:String, not:Boolean) extends LogicExpression with Ordered[Literal]
case class Conjunction(lits:Seq[Literal]) extends LogicExpression with Ordered[Conjunction]
...
I want every case class to be only Comparable to another instance of itself (Literal with Literal, Conjunction only with Conjunction, etc) but I would like to extend the trait in the abstract class so I don't have to repeat it on every subclass. Is this possible?
I tried
abstract class LogicExpression extends Ordered[LogicFormula]
but that would also allow comparing Literal with Conjunction for example.
You need something like this:
sealed trait LogicExpression[T <: LogicExpression[T]] extends Ordered[T]
case class SomeExpression() extends LogicExpression[SomeExpression] {
override def compare(that: SomeExpression) = ???
}

why trait can extend abstract class?

From the link
http://www.scala-lang.org/old/node/117
It gives an example that a trait extends an abstract class.
Since abstract class has constructor, how could it happen? Does it mean abstract class and trait have the same position?
They are for sharing interfaces, fields and type between classes and both of them are not instantiatable. And a abstract class extends a trait and vice versa.
But since A class in scala can extend only one superclass,
abstract class A
abstract class B
trait AA extends A
class C extends AA // ok class C's super class is A
class C extends B with AA // NG trying to have 2 super class
like I mentioned at the beginning, they are non-instantiatable.
So You do not need to care the abstract class's constructor.
It will be called when a class which extends it is created and instantiated.

Inheritance and traits

I found this reading another question:
"[...] a trait that extends a class puts a restriction on what classes can extend that trait - namely, all classes that mix-in that trait must extend that class"
a little example:
class C
trait U
trait T extends C
class D extends U with T // does not work
class E extends T with U // works
Apparently when traits inherit from classes, you have to put the trait in the position that you would otherwise place a class in (i.e. directly after extends)
Now to my questions:
(extended the previous example)
class C
class Test
trait U
trait T extends C
trait Tst extends Test
class D extends U with T // does not work
class E extends T with U // works
class Test2 extends Tst with T
what do we do when we want to inherit form two different traits, where each of those two inherit from a different class? (see class Test 2) this doesn't seem to be possible
if we need to pay attention to the placement of traits that extend a class, how do traits work then? Are traits inheriting from classes not "normal" traits anymore?
This is indeed impossible. You cannot inherit from two different classes at once, whether via traits or otherwise. This is unfortunate, but true. There is no very good reason for that AFAICT, it would be somewhat harder to implement, but not impossible, at least for scala (not "native java") classes. So apparently, it was just decided against at some point, seemingly without a good reason.
Traits that extend classes aren't really "abnormal". It's more like the way scala compiler handles them is. Basically, anything, that is or extends a class has to appear in the extends clause, and not in with. Why? Well, why can you not compare Strings in java with ==? because ...
Here's my guess: class can be defined with parameters, now let's imagine this:
class A(val x: Int)
class B extends A(1)
class C extends A(2)
trait D extends B
trait E extends C
// Oops! x = ? Doesn't compile of course
class F extends D with E
UPDATE:
Disclaimer: I'm not an expert in C++
Here's how C++ is solving the diamond problem:
class A {
int x;
public:
A(int _x) { x = _x; }
int getX() { return x; };
};
class B : virtual public A {
public:
// B b; b.getX == 1
B() : A(1) {}
};
class C : virtual public A {
public:
// C c; c.getX == 2
C() : A(2) {}
};
class D : public B, public C {
public:
// I need to know that B/C inherit A
// A(...) constructors defined above don't apply
D(): B(), C(), A(3) {}
};
I guess that's exactly the problem Scala is trying to avoid.

Inheriting constructor from parent class in scala

I'm trying to understand the syntax for inheriting one class from another and it seems I must announce the constructor parameters of the parent when I create the child?
Why does this code not compile?
class Animal(name:String)
class Dog extends Animal //Here is where compiler error occurs
But this does
class Animal(name:String)
class Dog(name:String ) extends Animal(name)
Is their a reason I must explicitly say extends Animal(name) and not just extends Animal and the constructor be implied?
The Scala Language Specification doesn't (as far as I can see) discuss the reasons, but providing an implied constructor would be a special case, and would arguably be less clear.
Note that you can do things like:
class Animal(name:String)
class Dog extends Animal("Dog")
and
class Animal(name:String)
class Dog(n1: String, n2: String) extends Animal(n1 + n2)
So the current behaviour accommodates a variety of patterns in a uniform and explicit way.
Let's say you have two constructors for Animal:
class Animal(name:String) {
def this() = this("unnamed")
}
Which of them would you expect class Dog(name:String) extends Animal to use?

How to get around of invariance of MongoRecord in Scala

Say I have a class defined as follows:
class A extends MongoRecord[A]{
}
Now I need to create a new class B, that is a subclass of A:
class B extends A{
}
Object B extends B with MongoMetaRecord[B]
The compiler would give an error like:
type arguments [B] do not conform to trait MongoMetaRecord's type parameter bounds [BaseRecord <: net.liftweb.mongodb.record.MongoRecord[BaseRecord]]
[error] object B extends B with MongoMetaRecord[B]
It seems that the class B inherits MongoRecord[A], but because of the invariance of MongoRecord, MongoRecord[B] cannot substitute MongoRecord[A]. And therefore class B does not conform to the type constraint. Any idea how to get around this problem? Thanks a lot.
You will not be able to get around the invariance but instead of having B a subclass A perhaps make an ALike trait instead. You could turn A into a trait and create an ARecord.
trait ALike {
// all the common stuff
}
class A extends ALike with MongoRecord[A] {
}
class B extends ALike with MongoRecord[B] {
}
Actually the code won't probably compile because the compiler will complain that method "meta" and "id" needs to be implemented with the proper types but the idea of the solution is in the right direction.
class A extends ALike with MongoRecord[A] with MongoId[A] { def meta = A }
class B extends ALike with MongoRecord[B] with MongoId[B] { def meta = B }
object A extends A with MongoMetaRecord[A]
object B extends B with MongoMetaRecord[B]
It's a late response but maybe someone else will find it useful ;)
abstract class A[U <: A[U]] extends MongoRecord[U] with ... with ObjectIdPk[U] with ... {
self: U =>
object text extends StringField(this, 255)
... // other fields
}
class B extends A[B] {
override def meta = B
... // add more fields or methods
}
object B extends B with MongoMetaRecord[B] {
...
}
You can use ProtoAuthUser[U] in place of MongoRecord[U] or any other similar trait.