Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Nested trait in class constructor in scala

I'm playing around with scala (scala 2.8). Suppose I have a class with a nested trait, and want to use that nested trait as the type for a parameter in the class's constructor. Is that even possible? This is the closest I've come:

class OuterClass(traitParam:OuterClass#InnerTrait) {
  trait InnerTrait { }
  val y:InnerTrait = traitParam
}

Without the third line that even compiles, but as soon as I try to actually use the traitParam as an InnerTrait I get a compiler error:

type mismatch; found: OuterClass#InnerTrait required: OuterClass.this.InnerTrait.

I can't figure out what (if anything) I could do. Doing

class OuterClass(traitParam:OuterClass.this.InnerTrait)

instead, as the error message might suggest, does not compile. Do I have any choice other than to move InnerTrait outside of OuterClass? If you're wondering why I would want to do this, the answer is that in my actual code, the equivalent of OuterClass has type parameters which would then be used in InnerTrait. If I move it outside, then I have to restate the type parameters every time I reference the inner trait.

like image 986
Micah Avatar asked Sep 03 '10 01:09

Micah


2 Answers

You're encountering Scala's path-dependent types. your val y: InnerTrait's type is specific to the instance in which it's contained. OuterClass#InnerTrait is a supertype of all the InnerTrait extant for all instances of OuterClass.

Try working with this:

class OuterClass(traitParam: OuterClass#InnerTrait) {
    trait InnerTrait { }

    type IT = OuterClass#InnerTrait

    def m1: IT = traitParam
}
like image 105
Randall Schulz Avatar answered Oct 26 '22 21:10

Randall Schulz


OuterClass has type parameters which would then be used in InnerTrait

So it is possible to have a: OuterClass and b: OuterClass such that these type parameters are different. For instance:

abstract class OuterClass[T] {
  val x: T
}

val a = new OuterClass[Int] { val x = 5 }
val b = new OuterClass[String] { val x = "abc" }

So here is the conundrum... InnerTrait must be tied to an instance of OuterClass, since each instance might have a different type parameter. However, you want to pass an InnerTrait as parameter to OuterClass constructor, so you'll need to construct InnerTrait before OuterClass. But since InnerTrait has to be tied to an instance of OuterClass, then OuterClass must be constructed before InnerClass, turning this into a chicken & egg problem.

There's something strange with that design, so I suggest you rethink it through.

like image 27
Daniel C. Sobral Avatar answered Oct 26 '22 21:10

Daniel C. Sobral