From e64b0bc9ecff90e437939a7150ba900a7912208c Mon Sep 17 00:00:00 2001 From: Sarah Haggarty Date: Thu, 3 Aug 2023 17:32:52 +0200 Subject: [PATCH] update: add definitely non-nullable types documentation --- docs/topics/generics.md | 67 +++++++++++++++++++ .../jvm/java-to-kotlin-nullability-guide.md | 30 +++++++++ docs/topics/null-safety.md | 1 + 3 files changed, 98 insertions(+) diff --git a/docs/topics/generics.md b/docs/topics/generics.md index 70ec337e3ad..d87f6964d9c 100644 --- a/docs/topics/generics.md +++ b/docs/topics/generics.md @@ -322,6 +322,73 @@ fun copyWhenGreater(list: List, threshold: T): List The passed type must satisfy all conditions of the `where` clause simultaneously. In the above example, the `T` type must implement _both_ `CharSequence` and `Comparable`. +## Definitely non-nullable types + +To make interoperability with generic Java classes and interfaces easier, Kotlin supports declaring a generic type parameter +as **definitely non-nullable**. + +To declare a generic type `T` as definitely non-nullable, declare the type with `& Any`. For example: `T & Any`. + +> The syntax represents an intersection between type `T` and the non-nullable type `Any`. +> +{type="note"} + +A definitely non-nullable type must have a nullable [upper bound](#upper-bounds). In addition, `Any` must resolve to `kotlin.Any`. + +The most common use case for declaring definitely non-nullable types is when you want to override a Java method that +contains `@NotNull` as an argument. For example, consider the `bar()` method: + +```java +import org.jetbrains.annotations.*; + +public interface A { + public T foo(T x) { return x; } + @NotNull + public T bar(@NotNull T x) {} +} +``` + +To override the `bar()` method in Kotlin successfully, you need `T` (and its subtypes) to be declared as definitely non-nullable: + +```kotlin +interface B : A { + override fun foo(x: T1): T1 + //Subtype T1 is definitely non-nullable + override fun bar(x: T1 & Any): T1 & Any +} +``` + +When working only with Kotlin, it's unlikely that you will need to declare definitely non-nullable types explicitly because +Kotlin's type inference takes care of this for you. Here is an example of how to declare definitely non-nullable types +explicitly in a Kotlin function: + +```kotlin +fun elvisLike(x: T, y: T & Any): T & Any = x ?: y + +fun main() { + // T is String + elvisLike("", "").length // OK + elvisLike("", null).length // Error: 'null' for non-nullable type + + // T is nullable String (String?) + elvisLike(null, "").length // OK + elvisLike(null, null).length // Error: 'null' for non-nullable type + + // Kotlin infers T is nullable String (String?) + elvisLike("", "").length // OK + elvisLike("", null).length // Error: 'null' for non-nullable type + elvisLike(null, "").length // OK +} +``` + +In this example, the `elvisLike()` function has two arguments `x` and `y`. `x` is a generic type whereas `y` is a generic +type that is definitely non-nullable. The function returns a value of definitely non-nullable type. The function body +contains the [elvis operator](null-safety.md#elvis-operator) to check "if `x` is not `null`, use it, otherwise use `y`". + +The [`length`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/length.html) property of the `String` class +can't be called on a `null` value. The compiler prevents this from happening by reporting an error whenever +`y` is a `null` value, because `y` is declared as definitely non-nullable. + ## Type erasure The type safety checks that Kotlin performs for generic declaration usages are done at compile time. diff --git a/docs/topics/jvm/java-to-kotlin-nullability-guide.md b/docs/topics/jvm/java-to-kotlin-nullability-guide.md index 31bac535736..20ebc8c3e34 100644 --- a/docs/topics/jvm/java-to-kotlin-nullability-guide.md +++ b/docs/topics/jvm/java-to-kotlin-nullability-guide.md @@ -116,6 +116,36 @@ on a value of a non-nullable type. Learn more about [calling Java from Kotlin in regard to null-safety and platform types](java-interop.md#null-safety-and-platform-types). +## Support for definitely non-nullable types + +In Kotlin, if you want to override a Java method that contains `@NotNull` as an argument, you need Kotlin's definitely +non-nullable types. + +For example, consider this `bar()` method in Java: + +```java +import org.jetbrains.annotations.*; + +public interface A { + public T foo(T x) { return x; } + @NotNull + public T bar(@NotNull T x) {} +} +``` + +To override the `bar()` method in Kotlin successfully, you need `T` (and its subtypes) to be declared as definitely +non-nullable (`T & Any`): + +```kotlin +interface B : A { + override fun foo(x: T1): T1 + //Subtype T1 is definitely non-nullable + override fun bar(x: T1 & Any): T1 & Any +} +``` + +Learn more about generic types that are [definitely non-nullable](generics.md#definitely-non-nullable-types). + ## Checking the result of a function call One of the most common situations where you need to check for `null` is when you obtain a result from a function call. diff --git a/docs/topics/null-safety.md b/docs/topics/null-safety.md index ee3bd46a04a..135a491fc3d 100644 --- a/docs/topics/null-safety.md +++ b/docs/topics/null-safety.md @@ -228,3 +228,4 @@ val intList: List = nullableList.filterNotNull() ## What's next? Learn how to [handle nullability in Java and Kotlin](java-to-kotlin-nullability-guide.md). +Learn about generic types that are [definitely non-nullable](generics.md#definitely-non-nullable-types).