views:

77

answers:

2

Does anyone know what's going on here with this compiler error? The error goes away if I don't extend INode.

trait AbsTypes
{
    type TKey
    type TValue
}

trait INode extends AbsTypes
{
    def get(key : TKey) : TValue
    def set(key : TKey, v : TValue) : INode
}

class ANode[TKey,TValue](
  val akey : TKey,
  val aval : TValue
) extends INode
{
    // ERROR : type mismatch;  found   : ANode.this.aval.type (with underlying type TValue)  required: ANode.this.TValue
    def get(key : TKey) : TValue = { aval }
    def set(key : TKey, v : TValue) : INode = {
        new ANode(key,v)
    }
}
+3  A: 

Generic parameters don't automatically override abstract types, even if they have the same names. Try renaming the generic parameters (to avoid name conflicts), and then declaring the types TKey and TValue in the method body.

class ANode[A,B](
  val akey : A,
  val aval : B
) extends INode {
    type TKey=A
    type TValue=B
    def get(key : TKey) : TValue =  aval 
    def set(key : TKey, v : TValue) : INode = new ANode(key,v)
}

I suppose it would be nice if the compiler emitted an error on the line where you specified the names of the generic types, instead of waiting until you started using those types.

Ken Bloom
Thanks, that solved this part, but I have a follow up question I'll post separately
NYCBrit
Could be worth adding here http://stackoverflow.com/questions/1332574/common-programming-mistakes-for-scala-developers-to-avoid
oluies
@Brent, is that a *common* error?
Ken Bloom
A: 

I don't have time unfortunately to test what I'm about to write but my understanding of your code is that each INode is going to get it's own TValue type. So the get operation really returns INode.this.TValue which is not compatible with another TValue type on another node.

The way to avoid this might be to write:

trait Nodes {
  type TKey
  type TValue

  trait INode {
   def get(key : TKey) : TValue
  }

  class ANode(
    val akey : TKey,
    val aval : TValue
  ) extends INode
}
Eric
He's still going to have the same problem with your code, because `akey` and `aval` are of the types named by the generics, not the abstract types. (Furthermore, if you compile only this code, you're not going to notice any compiler errors because you didn't try to use the conflicting types.)
Ken Bloom
Oh, yes, that's a copy and paste error. My intention was to use the types from the Nodes trait.
Eric
@Eric. I have edited your answer to reflect that intention, and removed my downvote.
Ken Bloom
Thanks, this would work, but it adds an unwanted reference to the outer type in my node instance. I'm trying to make the node as small/efficient as possible
NYCBrit