Search code examples
scalagenericsvar

Scala generics break reassignment to var


I am trying to get some generic classes to work, but I have not been able to make them compile. I have a generic Container class, in which I want to store an item and I have another generic class, which stores an item in the Container class:

final case class Container[A](var item: A) 

object Container {
  def FillContainer[A](item: A): Container[A] = {
    Container(item)
  }

  def setUpContainer[A]() = FillContainer[A](null.asInstanceOf[A])
}
class MyGenericClass[A] {
  def fill(item: A) {
    var myContainer = Container.setUpContainer()
    myContainer = Container.FillContainer(item) //type mismatch; found : A required: Null
  }
}

(I know that it is bad practice to use null in Scala, but here I sadly do not have much of a choice.)

First the Container myContainer should be initialized with some default values (in this case null) by the setUpContainer command. After that I want the same variable myContainer to hold another container with an actual item. But I get an error on the item in the FillContainer command in MyGenericClass: type mismatch; found : A required: Null and I don´t quite understand why. If I assign the return value of FillContainer immediately to the variable myContainer like so:

def fill(item: A) {
  var myContainer = Container.FillContainer(item)
}

it works perfectly fine. What is the difference between assigning the value immediately and reassigning it later?

Also if I do not use generics and use a String instead it does not complain either.

final case class StringContainer(var item: String) 

object StringContainer {
  def FillContainer(item: String): StringContainer = {
    StringContainer(item)
  }

  def setUpContainer() = FillContainer(null)
}


class StringClass {
  def fill(item: String) {
    var myContainer = StringContainer.setUpContainer()
    myContainer = StringContainer.FillContainer(item) //no problem
  }
}

Does anyone know what might cause this behaviour and how to fix it, so I can use the generic classes the same way as the String classes (i.e. First initializing the Container in a variable and after that overwriting the variable with a Container with an actual item)? Thank you in advance.


Solution

  • var myContainer = Container.setUpContainer()
    

    The type of this is not Container[A].

    setUpContainer returns a Container[X] for any X you choose (you have confusingly named X as A in the method definition of setUpContainer, but it is completely unrelated to the A of your item).

    Type-inference can only work if there is a starting point (usually a parameter type or the expected return type).

    Try

      var myContainer = Container.setUpContainer[A]()
    

    or

      var myContainer: Container[A] = Container.setUpContainer()