3

I'm trying to declare attribute of parametrized type inside anonymous class. This works in Java, in Scala (2.9) however I get compile error:

Parameter type in structural refinement may not refer to an abstract type defined outside that refinement

This is the code:

object DemoFail extends App {
  def it[T <: AnyRef](x: T) = new Iterator[T] {
    var i = x // here is the error
    def next = i
    def hasNext = true
  }
  for (i ← it(int2Integer(4))) println(i)
}

I can get it to work by "erasing" types manually:

object DemoOK extends App {
  def it[T <: AnyRef](x: T) = new Iterator[T] {
    var i: AnyRef = x
    def next = i.asInstanceOf[T]
    def hasNext = true
  }
  for (i ← it(int2Integer(4))) println(i)
}

So the question is: why can't the compiler do it for me ?

5
  • 3
    By adding a public variable to your iterator, you create a structural type that is a subtype of Iterator. It'll work if you change i to a private variable. Commented May 29, 2011 at 21:59
  • Indeed, I don't know how could I miss such an obvious solution. Commented May 29, 2011 at 23:54
  • @Kris: please respond below with an answer so I can properly accept it. Commented May 29, 2011 at 23:55
  • @Kris So this means that any access to i would happen through Java reflection, right? Commented May 30, 2011 at 7:22
  • I think that internal accesses would not use reflection, but you'd have to look at the bytecode to be sure. Commented Jun 10, 2011 at 16:24

3 Answers 3

1

By adding a public variable to your iterator, you create a structural type that is a subtype of Iterator. It'll work if you change i to a private variable.

Sign up to request clarification or add additional context in comments.

Comments

1

I am, unfortunately, not sure why this doesn't work. But here is an alternate workaround that avoids casts:

def it[T <: AnyRef](x: T) = {
  class Forever extends Iterator[T] {
    var i = x
    def next = i
    def hasNext = true
  }
  new Forever
}

1 Comment

This works because it avoids the structural type I mentioned above.
1

A quick fix would be to avoid the structural return type:

object DemoFail extends App {
  // The same with an explicit (non structural) return type
  //                       vvvvvvvvvvvvv
  def it[T <: AnyRef](x: T): Iterator[T] = 
    new Iterator[T] {
      var i = x // no more error
      def next = i
      def hasNext = true
    }
  for (i ← it(int2Integer(4))) println(i)
}

Indeed, method it on object DemoFail does not have an explicit return type. Hence this return type is inferred by the compiler.

Here, as you are overriding existing members and adding a new one to Iterator[T], the inferred return type of the method it is a structural type of the form Iterator[T] with Object {def next: T; var i : T; def hasNext: Boolean} (as an IDE like IntelliJ can suggest).

Thus you are defining a method whose return type is a structural type that uses an abstract type of this same method. This is what bothers scalac (structural type with same method's abstract type).

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.