Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Lower type bound on Scala field in mutable, covariant class?

I want to create a covariant class which is mutable, so I need to add a lower type bound to the setter method. But I also want the setter method to set a field, so I guess the field needs to have the same type bound?

class Thing[+F](initialValue: F) {

    private[this] var secondValue: Option[G >: F] = None

    def setSecondValue[G >: F](v: G) = {
        this.secondValue = Some(v)
     }
}

The method compiles fine. But the field called secondValue doesn't compile at all, with the error message:

    Multiple markers at this line
        - ']' expected but '>:' found.
        - not found: type G

What do I need to do?

like image 223
John Smith Avatar asked Aug 08 '12 06:08

John Smith


2 Answers

@mhs answer is right.

You can also use wildcard syntax (like in java), which has exactly the same meaning:

scala> :paste
// Entering paste mode (ctrl-D to finish)

class Thing[+F](initialValue: F) {
  private[this] var secondValue: Option[_ >: F] = None

  def setSecondValue[G >: F](v: G) = {
    this.secondValue = Some(v)
  }

  def printSecondValue() = println(secondValue)
}

// Exiting paste mode, now interpreting.

defined class Thing

scala> val t = new Thing(Vector("first"))
t: Thing[scala.collection.immutable.Vector[java.lang.String]] = Thing@1099257

scala> t.printSecondValue()
None

scala> t.setSecondValue(Seq("second"))

scala> t.printSecondValue()
Some(List(second))
like image 77
incrop Avatar answered Oct 21 '22 13:10

incrop


You need the forSome construct, which introduces G as existential type:

class Thing[+F](initialValue: F) {
  private[this] var secondValue: Option[G] forSome { type G >: F} = None

  def setSecondValue[G >: F](v: G) = {
    this.secondValue = Some(v)
  }
}

In your original code for secondValue, G has been pulled out of thin air, i.e., it hasn't been introduced properly. In case of setSecondValue the user (or the compiler) binds G at call site, but for a field that's not an option (especially, since yours is private). Read more about forSome and existential types in Scala here, here or here.

like image 30
Malte Schwerhoff Avatar answered Oct 21 '22 14:10

Malte Schwerhoff