Nullable Types
Basic Concept
To understand the compilation error in Null.kt, you must first understand
that the data types we normally use in a Kotlin program are non-nullable.
This means that an Int variable or a String variable, for example,
cannot have the value null.
This is quite useful. It means we can invoke a method or extension function
on an Int, a String or an instance of some other data type with complete
confidence, knowing that there is definitely an object there, on which the
requested operation can be performed.
However, nulls can also be useful. For example, if a function is not able to generate a sensible return value, it can be useful to signal this by returning a null, rather than by throwing an exception.
Besides, it is actually necessary for Kotlin to support the use of nulls, because Kotlin is supposed to integrate seamlessly with Java, and object references in Java can implicitly be null.
Kotlin addesses this by having a parallel type system, consisting of
nullable variants of the standard non-nullable types. These nullable variants
have the same name as their non-nullable counterparts, but with a ?
appended. Thus Kotlin has Int? to represent nullable integers, String?
to represent nullable strings, and so on.
The use of ? as a suffix is a clever mnemonic device. You can think of
Int?, for example, as meaning “could be an integer or could be null”,
whereas Int means “definitely an integer”.
It’s important to understand that there is no extra code required here.
The Kotlin standard library doesn’t have code to implement the String
class, plus additional code to implement the String? class.
Instead, you should think of nullability as a ‘label’ attached to a type
declaration to indicate a degree of uncertainty. It means that “a variable
of this type might represent the value null instead of a useful value”.
Now we can finally explain why the compilation error in Null.kt occurs.
The function readLine() has a return type of String?, meaning it might
return a String object or it might return a null. Thus the type of
variable input is also String?. The error occurs because printReversed()
is expecting a non-nullable string as an argument, but it is being given
a nullable string.
The Kotlin compiler is strict about using a value of a nullable type in places where a value of a non-nullable type is expected. It will allow this only if we explicitly check the value first, to make sure that it is not null.
Benefits of Strictness
To understand why Kotlin’s strict requirement for null checks is a good idea, consider what happens in the Java language.
In Java programs, there is always the possibility that an object reference
might be null, but the compiler doesn’t require references to be checked
before use. If a program attempts to invoke a method on an object but the
object reference is null, the result is a runtime error—specifically,
a NullPointerException (NPE).
NPEs can always be avoided through more careful programming, but Java developers often aren’t careful enough. Sometimes, an NPE ‘leaks out’ of an application and is embarrassingly visible to users—as in this example from 2018, of an NPE in a banking app:

This problem is much less common in Kotlin applications, thanks to the strictness of the Kotlin compiler and the ease with which null checks can be performed.