Conflict of nested inherited traits

Suppose I have the following code:

trait Trait1 { trait Inner { val name = "Inner1" } } trait Trait2 { trait Inner { val name = "Inner2" } } class Foo extends Trait1 with Trait2 { // I want Concrete1 to be a Trait1.Inner not a Trait2.Inner class Concrete1 extends Inner val c = new Concrete1 } object Obj { def main(args: Array[String]): Unit = { val foo = new Foo println(foo.c.name) } } 

When I mix in Trait1 and Trait2 , referring to Inner , the Inner type is used by default, no matter what attribute I mix per second; so when I call the Obj main method, it prints Inner2 . How can I access Trait1.Inner in Foo ? All three of the following compiler errors:

 class Concrete1 extends Trait1.Inner class Concrete1 extends Trait1$Inner class Concrete1 extends Trait1#Inner 
+7
scala traits
source share
4 answers

Instead

 class Concrete1 extends Inner 

Use this

 class Concrete1 extends super[Trait1].Inner 

That should get you what you want

+6
source share

There are two namespaces in the template (the template is the body of the class, object, or property).

  • Members: vals, vars, defs and nested objects
  • Types: alias types, nested attributes, and nested classes

When inheriting from multiple parent patterns, conflicts in these namespaces are resolved by linearizing the class.

You can reorder your inheritance to bring your desired Inner parent to your class or find an alternative design.

+4
source share

One option (if you can be invasive to hell) is to define each Inner trait as a member of a type that has a non-conflicting name.

 trait Trait1 { type Inner1 = Inner trait Inner { val name = "Inner1" } } trait Trait2 { type Inner2 = Inner trait Inner { val name = "Inner2" } } class Foo extends Trait1 with Trait2 { class Concrete1 extends Inner1 class Concrete2 extends Inner2 val c1 = new Concrete1 val c2 = new Concrete2 } object App extends Application { val foo = new Foo println(foo.c1.name) // Inner1 println(foo.c2.name) // Inner2 } 

If you cannot be invasive of the original traits (Trait1 and Trait2), you can expand them to define a type member.

 trait Trait1 { trait Inner { val name = "Inner1" } } trait Trait2 { trait Inner { val name = "Inner2" } } trait Trait1a extends Trait1 { type Inner1 = Inner } trait Trait2a extends Trait2 { type Inner2 = Inner } class Foo extends Trait1a with Trait2a { class Concrete1 extends Inner1 class Concrete2 extends Inner2 val c1 = new Concrete1 val c2 = new Concrete2 } 

Another approach would be to use an intermediate attribute to define your first concrete class:

 trait Trait1 { trait Inner { val name = "Inner1" } } trait Trait2 { trait Inner { val name = "Inner2" } } trait FooIntermediate extends Trait1 { class Concrete1 extends Inner } class Foo extends FooIntermediate with Trait2 { class Concrete2 extends Inner val c1 = new Concrete1 val c2 = new Concrete2 } 
+3
source share

Why not arrange the features in the order you expect them to take precedence? Linearization of signs is not arbitrary, but indicated.

+2
source share

All Articles