Reputation: 4701
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 ?
Upvotes: 3
Views: 1157
Reputation: 985
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).
Upvotes: 1
Reputation: 4580
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.
Upvotes: 1
Reputation: 167921
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
}
Upvotes: 1