Reputation: 4992
I have the following code:
trait CellT[VAL <: AnyVal] {
var value: VAL
type NEXT <: AnyVal
var next: CellT[NEXT]
}
abstract class Cell[VAL <: AnyVal] extends CellT[VAL] {
var next = this // defaults to `this`. ERROR
}
// impl example:
class CellInt extends Cell[Int] {
var value: Int = 0
}
The error says that
overriding variable next in trait CellT of type Cell[Cell.this.NEXT]; variable next has incompatible type
Here it is obvious that this
will have the type VAL <: AnyVal
which is the same as NEXT <: AnyVal
, however, I still get the error. How can I tell Scala that next
should be able to return anything of type Cell[A <: AnyVal]
, but this type should not be necessary the same as the class type parameter [VAL <: AnyVal]
??? Otherwise I could just use [VAL]
but it will be too restrictive, for example for Cell[Int]
it will restrict the next
method to return only Cell[Int]
type instances. But I want the next
to be reassignable to any other Cell[*]
types instances.
Upvotes: 0
Views: 134
Reputation: 6920
If you want next
to be reassignable to any other Cell[*] types instances, you can use existential types:
trait CellT[VAL <: AnyVal] {
var value: VAL
var next: CellT[_ <: AnyVal]
}
abstract class Cell[VAL <: AnyVal] extends CellT[VAL] {
var next: CellT[_ <: AnyVal] = this // defaults to `this`
override def toString = "Cell(%s,%s)".format(value, if(next == this) "this" else next.toString)
}
// impl example:
class CellInt extends Cell[Int] {
var value: Int = 0
}
class CellBoolean extends Cell[Boolean] {
var value = false
}
var c1 = new CellInt
var c2 = new CellBoolean
println(c1)
c1.value = 1
println(c1)
c1.next = c2
println(c1)
println(c2)
c2.value = true
println(c1)
println(c2)
Output:
Cell(0,this)
Cell(1,this)
Cell(1,Cell(false,this))
Cell(false,this)
Cell(1,Cell(true,this))
Cell(true,this)
Upvotes: 2
Reputation: 3304
This isn't exactly an answer so much as a warning. I wrote remarkably similar code a month ago, and it took me many iterations to learn that when it comes to Scala typing, coarser is better.
Keep in mind that Scala type parameter checking is compile-time only, so it is frequently coarser than you think. It's really annoying to spend 15 minutes getting your code to compile, only to discover that your X[Foo <: Bar] is getting treated as X[_].
I would recommend that you start with:
abstract class Cell[VAL] {
var value: VAL
var next: Cell[_]
}
and only get more specific if you have a pressing need. Chances are, if you need to know the type of next, you're going to need to do an explicit runtime check anyway.
Upvotes: 1
Reputation: 11366
Here it is obvious that this will have the type VAL <: AnyVal which is the same as NEXT <: AnyVal
No, they are not the same, they just share the same constraint. NEXT is not yet specified. Imagine that you subsequently subclass Cell like this:
class StringNextCell extends Cell {
type NEXT = String
}
Now, StringNextCell.next
is supposed to be of type Cell[String]
but your declaration from Cell declares it as Cell[Int]
Upvotes: 1