noncom
noncom

Reputation: 4992

Scala - same but different type

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

Answers (3)

Sergey Passichenko
Sergey Passichenko

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

David Leppik
David Leppik

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

stew
stew

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

Related Questions