============== Nullable Types ============== A First Example =============== Kotlin's ``readLine()`` function can be used to read a line of text from standard input. Let's investigate what it returns when called. #. In the Kotlin REPL, invoke ``readLine()`` and assign the returned value to a variable. Kotlin will wait for input at the point, so type some text and press Enter. Then query the value of the variable by entering its name at the prompt. Your interaction with the REPL should resemble this: .. code-block:: kotlin >>> val input = readLine() Hello >>> input res1: kotlin.String? = Hello Note, in particular, the type reported for the variable: ``String?``. #. Try querying the length property of the string. For example, if your variable is named ``input``, then enter ``input.length`` at the REPL prompt. What happens? #. The error message seen in the previous step notes that ``input`` is a 'nullable receiver'. If an object is of a nullable type, you cannot use the usual ``.`` operator to access a property or call a method; instead you must use the **safe call operator**, ``?.``. Try entering ``input?.length`` at the prompt. What happens now? What type of value is returned? (Look closely!...) #. Why does ``readLine()`` return a nullable string? Repeat the REPL interaction shown in Step 1 above, but this time instead of entering any text, press :kbd:`Ctrl+D` when Kotlin awaits your input. This closes the input stream before any input has been supplied. As a result, you should see that ``input`` has a value of ``null``. Kotlin uses the ``null`` value to signal that there was no input. If you had just pressed the Enter key instead of :kbd:`Ctrl+D`, the value of ``input`` would have been a zero-length string instead. Creating Nullable Variables =========================== If you wish to create your own nullable variable, append a question mark to the type name when declaring it. #. Try entering the following lines in the REPL: .. code-block:: kotlin var name: String? = "Joe" name = null ``name`` is a nullable string, which means its value can be either a string or ``null``. #. Repeat the above steps, using a type of ``String`` instead of ``String?``. This time, the assignment to ``name`` will fail. You can only assign ``null`` to variables of a nullable type. The Elvis Operator ================== Sometimes, we need to assign the result of computation to a variable and want that variable to be given a default value of some kind when the computation evaluates to ``null``. The 'null coalescing operator' or **Elvis operator**, ``?:``, provides a neat way of achieving this. #. Enter the following at the REPL prompt: .. code-block:: kotlin val input = readLine() ?: "NO INPUT" Enter some text, as before, then check the value and type of the ``input`` variable. The value should be the text you entered, and the type should be ``String``, not ``String?``. #. Repeat the previous step, but this time press :kbd:`Ctrl+D` instead of supplying input. If you check the ``input`` variable again, this time it should have a value of ``"NO INPUT"``. Again, the type will be ``String``, not ``String?``. The Elvis operator requires an expression that can evaluate to ``null`` on the left and a default value on the right. If the expression on the left is not ``null``, its value is used; otherwise, the value supplied on the right is used. Since this eliminates the possibility of a ``null`` result, the value returned by the Elvis expression is of a non-nullable type. #. The safe call and Elvis operators can be used together. Try this in the REPL: .. code-block:: kotlin readLine()?.length ?: 0 This will access the ``length`` property if ``readLine()`` returns a string, otherwise it will return 0. Consequently, you will see 0 displayed if you just press Enter or :kbd:`Ctrl+D`, otherwise you'll see a count of the number of characters you entered. The ``let`` Scope Function ========================== Kotlin provides several `scope functions`_ which allow you to execute a block of code within the context of a particular object. One of these, the ``let`` function, is often combined with the safe call operator to provide a neat way of making code execution conditional on a value being non-null [#let]_. #. Download :download:`passcheck.kt`. This is a mostly incomplete program that is supposed to check the validity of a password entered by the user. Edit the file and add the following code: .. code-block:: kotlin print("Enter a password: ") val password = readLine() Remember that ``readLine()`` here will return a nullable string. #. Now add the following: .. code-block:: kotlin password?.let { when { it in badWords -> println("Password forbidden") it.length < 8 -> println("Password too short") it.length > 24 -> println("Password too long") else -> println("Password OK") } } The code in the lambda function supplied to ``let`` will execute only when the value of ``password`` is non-null. Inside this lambda function, the ``password`` variable can be referenced as ``it``. #. Compile and run the program like so: .. code-block:: text kotlinc -include-runtime -d passcheck.jar passcheck.kt java -jar passcheck.jar .. _scope functions: https://kotlinlang.org/docs/reference/scope-functions.html .. rubric:: Footnotes .. [#let] This could also be achieved by testing explicitly for ``null`` with an ``if`` statement, but using safe call + ``let`` is a bit more elegant.