3
votes

Given the abstract definitions of the Outer class and its Inner class I would like to instantiate the concrete Inner1 class defined within Outer1 trait.

abstract class Outer {
  type Inner_Tp <: Inner;
  abstract class Inner {
    self: Inner_Tp =>
  }
}

trait Outer1 {
  self: Outer =>
  protected class Inner1 extends Inner {
    self: Inner_Tp =>
  }
  def Inner1() = new Inner1()
}

The Scala compiler prematurely terminates the compilation giving me the following error message: "error: class Inner1 cannot be instantiated because it does not conform to its self-type Outer1.this.Inner1 with Outer1.this.Inner_Tp". Why?

After all the Inner1 class is defined within an abstract context being its Outer1 trait. I would like to postpone the definition of type Inner_Tp until the trait gets mixed into some concrete class.

2

2 Answers

7
votes

For Inner1, the self-type says that it will always be instantiated together with the abstract type Inner_Tp. That's a promise that is not fulfilled at the instantiation point: the type is only Inner1 instead of Inner1 with Inner_Tp.

If you need to delay the definition of Inner_Tp, you also need to delay the creation of any instances that have it as a self-type. That is absolutely necessary, since you cannot produce a value of a type that you don't know yet. So better leave the method abstract. You may refine the abstract type as well:

trait Outer1 extends Outer {
   type Inner_Tp <: Inner1
   protected class Inner1 extends Inner

   def Inner1(): Inner_Tp
}

I'm not sure what you are after, but you may not need the self-types at all (I left them out for brevity already).

1
votes

Because the self: Inner_Tp tells that no subtype of Inner will be allowed to be instanciated unless it is a subtype of Inner_Tp too.

Rewriting self => Inner_Tp in Inner1 just restates the constraint, it does not satisfy it. To get a similar idea, when you have a descendant of an abstract class, if it does not implement the abstract method, you must write again that it is abstract. And you cannot instanciate. Same here, you restated that Inner_Tp is required, you did not make Inner_Tp available.

As long as Inner_Tp is an abstract type, you will not be able to mix it in, and so you will not be able to write new Inner1. You should probably introduce an abstract method that create Inners.