What is the difference between `fun <T> T?.foo(): ...
# getting-started
s
What is the difference between
fun <T> T?.foo(): T
and
fun <T: Any> T?.foo(): T
? Does one or both guarantee that the output will be non-null?
m
In the first example
T
can be a nullable type and the compile will force you to handle the possible
null
return from
foo
. I think the default type inference will be the non null, but you can force it.
null.foo<Any?>()
will have a return type of
Any?
s
In the first example, T can be any type, nullable or otherwise, and additionally, the receiver can be null even if T is given as a non null type. The return type is nullable if and only if T is given as nullable. Whereas in the second example, T must be non null, so the return type must be non null (but the receiver is nullable)
👍 2
s
@Sam I don't understand: isn't the type of T the same as the type of the receiver? How can the type be non-nullable if the receiver is nullable? Only by explicitly declaring the type in brackets?
m
The receiver will still be
nullable
with the second version, but
T
will not be so the return type will not be.
s
The receiver type is
T?
, so no, it's not the same as
T
. The added
?
means it can always be null, even if
T
itself is a non-null type.
e
Kotlin will infer the narrowest type reasonable, but with the first, both
Copy code
val x: String?
x.foo<String>()
x.foo<String?>()
are possible. with the second, only
Copy code
x.foo<String>()
is possible. (well plus supertypes, so
x.foo<Any>()
etc. may also be possible)
👍 1
s
but this version should be equivalent to the second, isn't it?
fun <T> T?.foo(): T & Any
(see definitely-non-nullable-types)