Instantiation of traits


#1

There’s a little bit of Scala syntax that puzzles me slightly:

scala> trait A
defined trait A

scala> trait B
defined trait B

You can’t instantiate a trait like this:

scala> new A
<console>:13: error: trait A is abstract; cannot be instantiated
       new A
       ^

You have to include an empty body:

scala> new A {}
res1: A = $anon$1@79957f52

You can, however, omit the body if you mix two traits:

scala> new A with B
res2: A with B = $anon$1@58886954

What is the reason for this difference?


#2

also asked at https://www.reddit.com/r/scala/comments/9t1b9u/instantiation_of_traits/


#3

It’s because in A with B, if A is a trait, the list of parents is extended to include the supertype of A, as per 5.1 in the spec.

Here is a counterexample. Eventually, traits will get parameters, of course.

scala> class X(i: Int)
defined class X

scala> trait A extends X
defined trait A

scala> trait B
defined trait B

scala> new A with B
<console>:14: error: not enough arguments for constructor X: (i: Int)X.
Unspecified value parameter i.
       new A with B
           ^

#4

It’s because in A with B , if A is a trait, the list of parents is extended to include the supertype of A , as per 5.1 in the spec.

But why the difference between new A with B and new A? Why not let new A mean new Object with A if A is a trait?

From a user’s perspective this irregularity is unexpected and confusing:

trait A
trait B
trait C
trait D
new A with B with C with D
new A with B with C
new A with B
new A {}

#5

It could get tricky picking a constructor, the class that is mixed into:

scala> class C ; class D extends C
defined class C
defined class D

scala> trait T extends C ; trait U extends D
defined trait T
defined trait U

scala> new T with U
<console>:14: error: illegal inheritance; superclass C
 is not a subclass of the superclass D
 of the mixin trait U
       new T with U
                  ^

scala> new D with T with U
res1: D with T with U = $anon$1@28157173

scala> new Object with T
<console>:13: error: illegal inheritance; superclass Object
 is not a subclass of the superclass C
 of the mixin trait T
       new Object with T
                       ^

It might be convenient to infer new T as T and not C with T.

scala> new C with T
res3: C with T = $anon$1@6a1568d6

scala> val t: T = new C with T
t: T = $anon$1@3b28b7b0

“Early definition” syntax is another case where with is significant in a way that can be confusing.

scala> class C extends { val i = 42 }
defined class C

scala> new C().i
res0: Int = 42

scala> trait T { val i: Int ; val j = i + 1 }
defined trait T

scala> class C extends { val i = 42 } with T
defined class C

scala> new C().j
res1: Int = 43