Expressions and Values
In this section we will focus on explaining how Kotlin Type System is built and how not having 'holes' in a system allow use to tread each instruction as a an expression which has a value.
(picture from : http://natpryce.com/articles/000818.html)
Why complete type system is so important? Without it you are unable to treat each expression as a value because what would be the value of :
throw new RuntimeException(...)
in Kotlin an if is an expression so you can assign it to a value
val cond=Math.random() > 0.5
val res: Int =if(cond) 1 else 2
Now imagine that one branch of this if would end with an exception
val res: Int =if(cond) 1 else throw Exception(..)
How you could assign throwing an exception to a variable? What is a type of such variable?
val d: () -> Nothing = { throw RuntimeException("...")}
Nothing lies at the bottom of the type system and is a subclass of every type so it is easy to actually assign it to any other type so that branches which throws an exception are correct from type system viewpoint.
Where is null?
Because Kotlin makes null very explicit as a part of type union so always union which can be a type or null so we can not pass Type? where Type is expected but we can use String where String? is expected because it is part of an Union.
However It would be dangerous to pass String? where Any is expected because Any can be any type but not null so this way union types are totally separated in different branch of type system.
So at the top we have Any? so you can safely substitute it with any type or null. At the very bottom we have Nothing. It has to be subtype of anything else so we ca not have Nothing? here because null is in separate branch.
Extensions for null unions
Now when you saw that null union is just a standard type somewhere in the type system then it should not be a surprise that you can add method extensions to this type in the same way you would ad it to standard type
fun String?.safeLength() = this?.length ?: 0
Displayer.section("nonNull length","nonNull".safeLength())
Displayer.section("Null length",null.safeLength())
Unit
Ok if everything in Kotlin is an expression and have a Type then what is a type of a function which theoretically just have some side effect? There is very special singleton type called Unit. At first sightg is looks like Java's void. But there is a big difference - void is just a keyword not a type so you can not use it as a generic type.
fun myprint(s:String):Unit = println(s)
Displayer.section("Only one empty set",Unit == Unit)
Smart and safe casting
- why smart?
//Because after if compiler knows that type has been checked and it is safe to use it.
val any:Any="aaa"
if(any is String){
Displayer.section("intelligent compiler",any.toUpperCase())
}
- why safe
//Because with the operator as? we can move to the union type level without raising an exception
val asint: String =any as String //ok
val asintExplode: Int? ="Aaa" as Int //will explode
val asintSafe: String? =any as? String //null-union value
val asintSafe2: Int? =any as? Int // null-union null
Extending nullable types
Because null union is as "first class citizen type" in Kotlin so you can easily add extension to it :
fun String?.safeLength() = this?.length ?: 0
Primitives
On syntax level you won't see difference between primitives and boxed primitives because you have only one type Int which is technically an object. They had method like standard objects and also here you can come across many operators
i > 3
i.compareTo(3)
public override operator fun compareTo(other: Int): Int
EXERCISES
FILE : ExpressionsAndValuesExercise
Exercise 1
- At the bottom of the file you can find Money class with ompanion object : implement of method with null safety.
- Finish implementation of an extension method for conversion of nullable Int into Money : fun Int?.toMoney()
Exercise 2
- At the bottom of the file you can Find Description class : Implement conversion from nullable String
Exercise 3
- Implement conversion of an Address object with nullable fields into String
Exercise 4
- Implement priceSummary method, handle null values.
Exercise 5
- Implement sendEmail method so that last email address can be checked thorugh : _lastSentWas. _If method receives null parameter you need to use default admins address : [email protected]