Silvio Mayolo
Silvio Mayolo

Reputation: 70267

Reference inner class from constructor

I have an immutable container-ish class.

class Foo[+T](val arg: T) {
  // ...
}

I want to create a subclass of Foo which has an inner object as its argument.

class Bar extends Foo[this.Inner.type](this.Inner) {
  object Inner {
    // ...
  }
  // ...
}

I would like it to be an inner object (and not a separate one) because I do need access to the private data within Bar. Yet when I try to compile that code, I get:

Example.scala:6: error: this can be used only in a class, object, or 
class Bar extends Foo[this.Inner.type](this.Inner) {
                      ^
Example.scala:6: error: this can be used only in a class, object, or template
class Bar extends Foo[this.Inner.type](this.Inner) {template
                                       ^

Is it possible to call the superclass constructor using inner objects as arguments? And if so, what am I doing wrong?

EDITED

In response to some comments, I figure I should give a few more specifics. My class Foo is actually specialized as Foo[+T <: SomeAbstractClass] and it has several operations defined on it that operate on SomeAbstractClass instances. I want to create a subclass Bar which behaves both as a Foo and its underlying SomeAbstractClass. Since I can't have Bar inherit from both classes, I figured an inner object was the next best thing. Really, what I want specifically is a Bar and an Inner which behave as a Foo container and a SomeAbstractClass element, respectively, and which have complete access to each other's private variables.

Upvotes: 1

Views: 390

Answers (2)

Silvio Mayolo
Silvio Mayolo

Reputation: 70267

wheaties' answer explains why this can't be done the way I wanted to do it, but I figured I would post the solution that got a similar effect for me. I ended up writing an outer class which contains both the Bar and the Inner, which can interact freely with the right access modifiers on the variables.

class BarContainer {
  object Bar extends Foo[Inner.type](this.Inner) {
    // Any private fields should be declared private[BarContainer]
    // ...
  }
  object Inner {
    Bar.x = 3
    // ...
  }
}

Upvotes: 0

wheaties
wheaties

Reputation: 35970

What you are trying to do can't be done due to the virtue of the path dependent nature of your inner object. That is, every time you do the following:

val obj1 = new Bar(...){
  def lala(inner: Inner) = ...
}
val obj2 = new Bar(...)

obj1.lala(obj2.Inner) //won't compile!!

the actual Inner object is redefined. It won't compile because Inner on obj1 is not the same Inner on obj2. They aren't the same type!

Hence, what you are trying to do is reference a definition of something before it can be fully scoped and defined. This is one of the reasons why the compiler is going to complain.

Upvotes: 1

Related Questions