Scala Type Mismatch underlying type and class vs method

generics, scala, type-mismatch

Solution

The problem in your code is type parameter shadowing.

You have:

class ThreeStacks[A, B, C](val stackSize:Int  = 1000) {
  def push1[A](value: A): Unit = stack1.push(value)
  ...
}

It should be:

class ThreeStacks[A, B, C](val stackSize:Int  = 1000) {
  def push1(value: A): Unit = stack1.push(value)
  ...
}

The way you have done it, type parameter `A` of class `ThreeStacks` and type parameter `A` of method `push1` are completely different ones and thus, are incompatible with each other. The same applies to `B` and `C`.

Problem

I'm implementing a class that acts as three stacks that rely on the same array (from Gayle Laakmann's cracking the coding interview). I'm having trouble understanding why this code results in type mismatches: ``` class ThreeStacks[A, B, C ](val stackSize:Int = 1000) { /** * Push a value on to the first stack * @param value value of type A */ def push1[A](value :A): Unit = stack1.push(value) /** * Push a value on to the second stack * @param value value of type B */ def push2[B](value: B): Unit = stack2.push(value) /** * Push a value on to the third stack * @param value value of type C */ def push3[C](value: C): Unit = stack3.push(value) /** * Pops the top value off the first stack * @return Some(value) at the top of the stack, None if the stack is empty */ def pop1[A](): Option[A] = stack1.pop() /** * Pops the top value off the second stack * @return Some(value) at the top of the stack, None if the stack is empty */ def pop2[B](): Option[B] = stack2.pop() /** * Pops the top value off the second stack * @return Some(value) at the top of the stack, None if the stack is empty */ def pop3[C](): Option[C] = stack3.pop() // the shared stacks private val stack1 = SharedStack[A]() private val stack2 = SharedStack[B]() private val stack3 = SharedStack[C]() // the shared stack class is simply a container for push and pop functions class SharedStack[T](val push: T => Unit, val pop: () => Option[T]) // the sharedstack object is a factory setups a shared stack object with its proper push/pop functions that are received // from the stackmemory instance private object SharedStack{ val stackMemory = new StackMemory(stackSize) def apply[T](): SharedStack[T] = { val stackTuple = stackMemory.registerStack[T]() new SharedStack(stackTuple._1, stackTuple._2) } } // the memory object responsible for handling the sharing of the array private class StackMemory(val stackSize: Int = 1000){ // helps prevent the conflict warnings with immutable and mutable collections private val MutableMap = scala.collection.mutable.Map // the array that contains the stack nodes private val array = new Array[Option[StackNode[Any]]](stackSize) // keeps track of the heads of all the stacks private val registeredStackHeads = MutableMap[Int, Int]() // an index to help assign every new stack a unique key private var nextRegistrationIndex = 1 // a list of indices in the array that have been freed private var freedIndices = List[Int]() // the next available free index, increments till it reaches the end of the array, different from the freeIndices list // in that it only is concerned with free cells while they are available at the end of the array private var nextFreeIndex = 0 /** * Registers a stack within the memory object and returns the push/pop functions * @return the push/pop functions relevant for that stack */ def registerStack[T](): (T => Unit, () => Option[T]) = { val index = nextRegistrationIndex val noPreviousValueIndex = -1 // register the index in the stack heads with an empty value registeredStackHeads(index) = noPreviousValueIndex nextRegistrationIndex += 1 (push[T](index), pop[T](index) ) } /** * Returns the push function for a stack at the given index * @param stackIndex the index of the requesting stack * @return the push function for the stack */ def push[T](stackIndex: Int) = { (value: T) => { // get the indices and initialize a stack node val headIndex = registeredStackHeads(stackIndex) val index = nextAvailableIndex() val stackNode = new StackNode[T](headIndex, value) // store the new stack head and place it in to the array registeredStackHeads(stackIndex) = index array(index) = Some(stackNode) } } /** * The pop function for the stack at a given index * @param stackIndex the index of the requesting stack * @return the pop function for the stack */ def pop[T](stackIndex: Int): () => Option[T] = { () => { val headIndex = registeredStackHeads(stackIndex) if(headIndex < 0) None else { array(headIndex) match { case Some(s : StackNode[T]) => { registeredStackHeads(stackIndex) = s.previousIndex freeIndex(headIndex) Some(s.value) } case _ => None } } } } // retrieve the next available index, throws an exception if there are no available indices private def nextAvailableIndex():Int = { // return a new index if the array isn't full otherwise throw an exception def newIndex() : Int = { if(nextFreeIndex >= stackSize){ throw new Exception("No more room in stack array available") } else{ val index = nextFreeIndex nextFreeIndex += 1 index } } // first check if any of the old indices have been freed freedIndices match { case Nil => newIndex() case head::tail => freedIndices = tail; head } } // frees an index and adds it to the free indices list private def freeIndex(i: Int): Unit = { if (i >= array.length) throw new ArrayIndexOutOfBoundsException("The index to be freed does not exist in the array") array(i) = None freedIndices = i::freedIndices } // covariant node that helps keep track of the previous index of the stack private class StackNode[+S](val previousIndex: Int, val value: S) } } ``` The code works like its suppose to if I call stack1.push or stack1.pop but it causes type mismatches on wrappers push1 and pop1, why is this happenning? ``` example for push1: type mismatch; found : value.type (with underlying type A) required: A def push1[A](value :A): Unit = stack1.push(value) example for pop1: type mismatch; found : Option[A(in class ThreeStacks)] required: Option[A(in method pop1)] def pop1[A](): Option[A] = stack1.pop() ```

Original source