not sure if there is a better channel but what is ...
# getting-started
p
not sure if there is a better channel but what is the advantage of definitely non nullable types?
j
It was necessary in some cases of implementing some java interfaces as far as I remember, but most of the time in pure Kotlin it's redundant
r
I think in cases like these it's needed iirc?
Copy code
class Collection<T> {
    fun getOrElse(key: Int, default: T & Any): T & Any
}
p
Ah. makes sense. but I can’t think of practical applications where I would prefer this over using a bound on the type param itself
t
Example: You want to write your own elvis-operator-like function, then you cannot restrict your type:
Copy code
fun <T> getOrDefault(nullable: T, default: T & Any): T & Any
Edit: You just used the same example in the channel, mea culpa...
v
How is the other version restricted?
x
is still nullable, isn't it? Where is the difference between the two examples of OP besides the second one being more readable and looking more idiomatic?
r
@Tobias Suchalla What advantage does that provide over:
Copy code
fun <T: Any> getOrDefault(nullable: T?, default: T): T
v
That's exactly the question
r
@Vampire Ah, it seems I missed some context between the time you wrote your comment and @Tobias Suchalla edited theirs. My bad 🙂
v
No, my answer was after his edit. 😛
r
In that case, I am clearly just confused
t
I just reiterated what I thought to have read somewhere.. 😄 But the KEEP and anouncement mention Java interop as the main driver behind this solution as Java does not support explicit nullability. In a pure Kotlin environment it does indeed seem to be unnecessary^^
d
Imagine you have two classes: Foo<T> and Bar<T : Any>. Now add Bar as a val of Foo without modifying Foo's type parameter.
The getOrElse posted above also qualifies, as you cannot correctly introduce a new type parameter there.
As a pure Kotlin example, Bar could be KClass.
j
The getOrElse posted above also qualifies, as you cannot correctly introduce a new type parameter there.
The
getOrElse
above is a member function, which means if you control it you also control the class itself. You could declare the class with
T : Any
and add
T?
everywhere instead of
T
, and use
T
instead of
T & Any
.
Now add Bar as a val of Foo without modifying Foo's type parameter.
You control
Foo
here, so you can change `Foo`'s parameter (and again, update all
T
to
T?
). Or do you mean it's about backwards compatibility? That could be a fair point.
d
It may not be correct to change the parameter. Let Foo be ColumnType<T>, where T represents the type you can get out of an object (eg fun <T> get(c: ColumnType<T>). And you need the KClass inside ColunnType.
Changing <T> to <T : Any> and adding T? places does not in general retain the same semantics, as you have introduced definitely nullable types where they were not before.
👍 1
j
Ah I see what you mean. You want the user to be able to distinguish
ColumnType<String>
from
ColumnType<String?>
, and yet be able to represent the non-nullable
KClass<String>
in both cases. That makes sense, thanks!
r
Exactly
j
Changing <T> to <T : Any> and adding T? places does not in general retain the same semantics, as you have introduced definitely nullable types where they were not before.
Indeed, for some reason I missed this.
d
This is exactly the form of the Java class I realized couldn't move to Kotlin yet last week 😃
j
Haha I feel you. Still, I think the example in the release notes is poorly chosen, as it doesn't really show the benefit of definitely-not-null types since that use case could be expressed before with
<T : Any>
(since the function itself is generic and only takes
T
as input, it is safe to introduce definitely nullable type): https://kotlinlang.slack.com/archives/C0B8MA7FA/p1652773490430979