Tomer
04/04/2025, 2:10 PM@UnsafeVariance
. If I am defining some Container<out T>
class and I want one of its methods to return Optional<T>
(for Java users), then is it safe/reasonable to do Optional<@UnsafeVariance T>
? I don't want to do Optional<out T>
since that will end up being Optional<? extends T>
for Java users, which is annoying to work with.
I think using @UnsafeVariance
here makes sense because Optional
is an immutable container so you can only get T
out of it; you can't put a new T
into an existing Optional<T>
. It's just that Java obviously does not define Optional
with out T
at it's declaration (since it's not Kotlin)
Am I making sense? Am I missing anything here?Dmitry Khalanskiy [JB]
04/04/2025, 2:33 PMimport java.util.Optional
class Container<out T>(val v: T?)
fun <U: Any> Container<U>.optional(): Optional<U> =
Optional.ofNullable(v)
fun main() {
val c = Container(3)
println(c.optional())
}
Tomer
04/04/2025, 2:34 PMDmitry Khalanskiy [JB]
04/04/2025, 2:35 PMI would have assumed they get exposed as standalone functions that take the receiver as the first parameter or somethingThat's exactly what happens, yes.
Tomer
04/04/2025, 2:36 PMTomer
04/04/2025, 2:36 PMContainer<out T>
thing was a simplified example vs what the class actually doesTomer
04/04/2025, 2:37 PM@UnsafeVariance
is correctTomer
04/04/2025, 2:37 PMDmitry Khalanskiy [JB]
04/04/2025, 2:46 PM@UnsafeVariance
is fine in your case. The reason Kotlin forbids just returning Optional<T>
is code like this:
interface MutableOptional<T> {
fun mutate(newValue: T)
}
class Container<out T>(v: T) {
private var vValue: T = v
fun optional(): MutableOptional<@UnsafeVariance T> = object: MutableOptional<@UnsafeVariance T> {
override fun mutate(newValue: @UnsafeVariance T) {
vValue = newValue
}
}
val v: T get() = vValue
}
fun main() {
val c = Container<Int>(3)
val c2: Container<Any?> = c
val o: MutableOptional<Any?> = c2.optional()
o.mutate("4.3")
println(c.v + 10) // throws an exception
}
When it comes to just the variance, Optional
and MutableOptional
are the indistinguishable.
Java's Optional
could have been marked with out
as well, which means that your users can't really do anything with it that would break the guarantees of your container.Tomer
04/04/2025, 2:48 PMOptional<T>
is because the container cannot be mutated, right?Dmitry Khalanskiy [JB]
04/04/2025, 2:49 PMTomer
04/04/2025, 2:49 PM