Generics with Nullability in Kotlin



You may have seen or read a lot about Generics and various problems that it creates if not used in a certain way.
Like Java, classes in Kotlin may have type arguments. Not only classes but functions in Kotlin can too have type parameters. It comes with Declaration-site variance and Type Projections to avoid the problem we faced with Generics in Java. Here we will not dive further into these topics, will cover it later in another blog.
Let’s try to define Generics in simple terms. First, note that Generics is not a Type. (You know the types right? like Int, String, Boolean and so on).
You can think of Generic as “Function of Types” so by applying it to Type/Types to generate a Type.
To understand what it means, let’s define it with an example, In your laptop, file folder (or DIR) may have different types of documents like Excel, CSV, PDF, etc.
1 interface Folder<DOCUMENT> {
2   fun save(type: DOCUMENT)
3   fun print(type: DOCUMENT)
4   fun delete(): DOCUMENT
5 }
Here, we have defined interface Folder which takes a type argument DOCUMENT. For you to make it easy to understand type argument is named as DOCUMENT, You can replace it with any name like D or T.
1 class Folder<Excel>
2 
3 class Folder<PDF>
And Folder is not a type but a class that takes a type and produces a type. Both Folder<Excel> and Folder<PDF> are types but not classes. I hope till now it’s clear to you.
Let’s move to the main topic, Generics with Nullability. It can be also called a Generics compose type. Keep one thing in mind while using Generics in Kotlin, Generic type parameter T is nullable without “?”. It means Type variables are nullable, even though they do not have a “?” suffix.
Note: In Kotlin to define any type as nullable, you have to use nullability operator i.e.”?” eg. String?
For example, the List defined below with type parameter T may contain null.
1 fun <T> listof(vararg items: T): List<T> = ...
Sometimes, you may want to constrain a list using generics to have only non-null values.
let’s say you want to filter given Iterable collection to get only non-null values as List. To do so, constrain a type parameter to be a subtype of Any.
Note: Any is the ultimate supertype of all classes except its values, are never null.
See the below example -
1 fun <T: Any> Iterable<T?>.filterNotNull(): List<T> = ...
I hope, you have got a fair idea about this topic.

Comments