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?
@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))
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With