Implementing inner traits in Scala like we do with inner interfaces in Java
Asked Answered
A

2

11

This code in Java compiles without errors:

interface T {
    interface Q {
    }
}

class C implements T.Q {
}

whereas this code in Scala does not:

trait T {
    trait Q {
    }
}

class C extends T.Q {
}

What is the correct translation (if it exists) of the Java code listing into Scala?

Theoretical explanations about language design are welcome.

Agnesse answered 25/3, 2013 at 12:22 Comment(2)
In addition to what others have already answered about path-dependent types, it is also worth noting that Scala's notation for Java's T.Q is T#Q.Omentum
The T#Q syntax Oleg referred to is called a type projection. And note that you can extend Q if you do it within a type derived from T, e.g. class A extends T { class B extends Q }.Gentlewoman
Z
11

The inner type Q is defined only for specific instance implementation of the T trait. Since scala has path-dependent types, each instance of T will have his own subtrait Q.

scala> trait T {
     |   trait Q
     | }
defined trait T

scala> class C extends T {
     |   def getQ: this.Q = new this.Q {}
     | }
defined class C

scala> val inC = (new C).getQ
inC: C#Q = C$$anon$1@3f53073a


scala> val c = new C
c: C = C@1a7e4ff0

scala> new c.Q {}
res4: c.Q = $anon$1@36bbb2f5

If you need an interface for a generic behavior for your clients to implement, and not dependent on a specific C instance, you should define it within an Object

scala> object T {
     |   trait Q {
     |     def implementMe: Unit
     |   }
     | }
defined module T

scala> val inT = new T.Q {
     |   def implementMe = println("implemented!")
     | }
inT: T.Q = $anon$1@20f2a08b

scala> inT.implementMe
implemented!

Why path-dependent types?

As for the design reasons, look here

Zarf answered 25/3, 2013 at 13:52 Comment(0)
B
3

You cannot do that. When types are nested you're creating what is called a path-dependent type, meaning the type of each instance of the inner entity is tied to the specific instance within which it's constructed.

In other words, you interface Q has no independent existence that would allow you to refer to it apart from an instance of T.

Berkman answered 25/3, 2013 at 13:40 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.