I've tried two ways to constrain a generic type parameter to a nullable type, but both seem to have some unexpected problems.
First attempt (using T <: AnyRef):
scala> def testAnyRefConstraint[T <: AnyRef](option:Option[T]):T = {
| //without the cast, fails with compiler error:
| // "found: Null(null) required: T"
| option getOrElse null.asInstanceOf[T]
| }
testAnyRefConstraint: [T <: AnyRef](Option[T])T
scala> testAnyRefConstraint(Some(""))
res0: java.lang.String =
scala> testAnyRefConstraint(Some(0))
<console>:16: error: inferred type arguments [Int] do not conform to method testAnyRefConstraint's type parameter bounds [T <: AnyRef]
testAnyRefConstraint(Some(0))
This seems to do exactly what I want, but I don't understand why the null needs to be cast to a T.
Second attempt (using T >: Null):
scala> def testNullConstraint[T >: Null](option:Option[T]):T = {
| option getOrElse null
| }
testNullConstraint: [T >: Null](Option[T])T
scala> testNullConstraint(Some(""))
res2: java.lang.String =
scala> testNullConstraint(Some(0))
res3: Any = 0
This doesn't require the cast on null, but it allows AnyVals to be passed and converts the type to any, which is not what I was looking for.
Does anyone have any idea why these two different approaches work the way that they do?
def testAnyRefConstraint[T >: Null <: AnyRef](option:Option[T]):T = {
option getOrElse null
}
I felt really stupid when I made this error the first time. Just because something extends AnyRef
doesn't mean it must be nullable. For instance, Nothing
is a subtype of AnyRef
, and it is not nullable.
The other way around is similar, because Any
is a supertype of Null
, and any Int
is also an Any
.
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