An introduction to Kotlin type system
An introduction to Kotlin type system
and more
Kotlin is a ..., statically typed,
..., programming language.
-wikipediaKotlin is a ..., statically typed,
..., programming language.
What is a type?
What is a type?
What is a type?
What is a class?
What is a type?
What is a class?
What is an object?
Object vs Class
Object vs Class
Class is a blueprint or template from which objects are created.
Object is an instance of a class.
Object vs Class
Class is a blueprint or template from which objects are created.
Object is an instance of a class.
class A
Object vs Class
Class is a blueprint or template from which objects are created.
Object is an instance of a class.
class A
val x = A()Class vs Type
A type summarizes the common features of a set of objects with the same characteristics. We may say that a type is an abstract interface that specifies how an object can be used.
Class vs Type
A type summarizes the common features of a set of objects with the same characteristics. We may say that a type is an abstract interface that specifies how an object can be used.
A class represents an implementation of the type. It is a concrete data structure and collection of methods.
A data type (or simply type) is a collection or grouping of data values, usually specified by a set of possible values, a set of allowed operations on these values, ... A data type specification in a program constrains the possible values that an expression, such as a variable or a function call, might take.
-wikipediaWe can define our types by defining classes, interfaces, Enums, ...
Every classifier, i.e. classes and interfaces, generates a set of types.
Every classifier, i.e. classes and interfaces, generates a set of types. In most cases, it generates a single type, but an example where a single class generates multiple types is a generic class:
Every classifier, i.e. classes and interfaces, generates a set of types. In most cases, it generates a single type, but an example where a single class generates multiple types is a generic class:
class Box<T>
We can say that in the above snippet we see definition of class A, but the type of x is A. Therefore A is both a name of the class and of the type. The class is a template for an object but concrete object have a type. Actually, every expression has a type!
class A
val x = A()We can say that in the above snippet we see definition of class A, but the type of x is A. Therefore A is both a name of the class and of the type. The class is a template for an object but concrete object have a type. Actually, every expression has a type!
class A
val x = A()Statement vs Expression
Statement vs Expression
An expression in a programming language is a combination of one or more explicit values, constants, variables, operators and functions that the programming language interprets and computes to produce another value.
An expression has a value, which can be used as part of another expression.
Statement vs Expression
In computer programming, a statement is the smallest standalone element of an imperative programming language that expresses some action to be carried out.
Java type system
Java type system
Object
Java type system
Object
Number
MyClass
String
Java type system
Object
Number
MyClass
String
Integer
MySubClass
Kotlin type system
Any
Kotlin type system
Any
Number
MyClass
String
Kotlin type system
Any
Number
MyClass
String
Int
MySubClass
Kotlin type system
Any
Number
MyClass
String
Int
MySubClass
Nothing
Kotlin type system
Any
Number
MyClass
String
Int
MySubClass
Nothing
Object
=
Kotlin type system
Any
Number
MyClass
String
Int
MySubClass
Nothing
Object
=
?
Kotlin type system
Any
Number
MyClass
String
Int
MySubClass
Nothing
Object
=
?
Object test = nullKotlin type system
Any
Number
MyClass
String
Int
MySubClass
Nothing
Object
=
?
Object test = nullval test: Any = nullKotlin type system
Any
Number
MyClass
String
Int
MySubClass
Nothing
Any?
subtyping by
Nullablitiy
Kotlin type system
Any
Number
MyClass
String
Int
MySubClass
Nothing
Any?
Number?
MyClass?
String?
Int?
MySubClass?
Nothing?
Kotlin type system

Kotlin type system
When we define a class
class MyClass
We automatically have 2 types available
Kotlin type system
When we define a class
class MyClass
We automatically have 2 types available
val a: MyClass
val b: MyClass?
Kotlin type system
A type without a question mark denotes that variables of this type can’t store null references. This means all regular types are non-nullable by default, unless explicitly marked as nullable.
Kotlin type system
Once you have a value of nullable type, the set of operations you can perform on it is restricted. For example, you can no longer call methods on it. The compiler will now complain about the call to length in the function body:
fun main() {
val x: String? = null
var y: String = x
// ERROR: Type mismatch:
// inferred type is String? but String was expected
}
Kotlin type system
fun strLen(s: String?) = s.lengthKotlin type system
fun strLen(s: String?) = s.lengthError: Only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable receiver of type String?
Kotlin type system
fun strLenSafe(s: String?): Int =
if (s != null) s.length else 0Kotlin type system
fun strLenSafe(s: String?): Int =
if (s != null) s.length else 0Once you perform the comparison, the compiler remembers that and treats the value as non-nullable in the scope where the check has been performed.
Kotlin type system
Note: At runtime, objects of nullable types and objects of non-nullable types are treated the same: A nullable type isn't a wrapper for a non-nullable type. All checks are performed at compile time. That means there's almost no runtime overhead for working with nullable types in Kotlin.
Kotlin type system

safe-call operator
Kotlin type system

Elvis operator
val x =
Kotlin type system

safe-cast operator
Kotlin type system
non-null assertion operator

Kotlin type system

Kotlin type system

Kotlin type system
kotlin.Any
Kotlin type system
Besides being the unified supertype of all non-nullable types, kotlin.Any must also provide the following methods.
kotlin.Any
Kotlin type system
Besides being the unified supertype of all non-nullable types, kotlin.Any must also provide the following methods.
public open operator fun equals(other: Any?): Boolean
public open fun hashCode(): Int
public open fun toString(): String
kotlin.Any
Kotlin type system
kotlin.Nothing
Kotlin type system
kotlin.Nothing is an uninhabited type, which means the evaluation of an expression with kotlin.Nothing type can never complete normally. Therefore, it is used to mark special situations, such as
- non-terminating expressions
- exceptional control flow
- control flow transfer
kotlin.Nothing
Kotlin type system
kotlin.Nothing
fun fail(message: String): Nothing {
throw IllegalStateException(message)
}
val address = company.address ?: fail("No address")
println(address.city)Kotlin type system
kotlin.Unit is a unit type, i.e., a type with only one value; all values of type kotlin.Unit should reference the same underlying kotlin.Unit object. It is somewhat similar in purpose to void return type in other programming languages in that it signifies an absence of a value (i.e. the returned type for a function returning nothing), but is different in that there is, in fact, a single value of this type.
kotlin.Unit
Kotlin type system
kotlin.Unit
public object Unit {
override fun toString() = "kotlin.Unit"
}Kotlin type system
Where is null on the hierarchy?
When we declare a property without explicitly indicate its type and assigning null as its value, its type will be determined as Nothing? that’s because this is the data type of null. Null is the only possible instance of Nothing?, there is not an object which type is specifically Nothing?
Kotlin type system
Where is null on the hierarchy?
At code level we can be totally sure that when we see a property which type is Nothing? the only possible value it can keep is null. Also, since Nothing is the subtype of all types, null can be used as the nullable version of any type we declare.
Kotlin type system
Where is null on the hierarchy?
fun print(value: Any?) = println(
when (value) {
is String -> "value is string"
is Int -> "value is int"
else -> "value unknown"
}
)Kotlin type system
Where is null on the hierarchy?
fun print(value: Any?) = println(
when (value) {
is String -> "value is string"
is Int -> "value is int"
is null -> "value is null"
else -> "value unknown"
}
)Kotlin type system
Where is null on the hierarchy?
fun print(value: Any?) = println(
when (value) {
is String -> "value is string"
is Int -> "value is int"
is null -> "value is null"
else -> "value unknown"
}
)error: type expected
Kotlin type system
Where is null on the hierarchy?
fun print(value: Any?) = println(
when (value) {
is String -> "value is string"
is Int -> "value is int"
is Nothing? -> "value is null"
else -> "value unknown"
}
)Kotlin type system
Generic types are, by default, nullable
fun <T> printer(value: T) {
print("Printing the value: "+ value)
}
printer("Hola")
printer(1)
printer(1.1)
printer(null)Kotlin type system
Generic types are, by default, nullable
If we don’t want to allow null values we need to modify our example as below:
fun <T: Any> printer(value: T) {
print("Printing the value: "+ value)
}data class User (
val firstName: String?,
val lastName: String?
)
fun hasValidData(user: User): Boolean{
val firstName = user.firstName ?: return false
val lastName = user.lastName ?: return false
return firstName.isNotBlank() && lastName.isNotBlank()
}Kotlin type system
data class User (
val firstName: String?,
val lastName: String?
)
fun hasValidData(user: User): Boolean{
val firstName = user.firstName ?: return false
val lastName = user.lastName ?: return false
return firstName.isNotBlank() && lastName.isNotBlank()
}What is the inferred type?
Kotlin type system
data class User (
val firstName: String?,
val lastName: String?
)
fun hasValidData(user: User): Boolean{
val firstName: String = user.firstName ?: return false
val lastName = user.lastName ?: return false
return firstName.isNotBlank() && lastName.isNotBlank()
}What is the inferred type?
Kotlin type system
data class User (
val firstName: String?,
val lastName: String?
)
fun hasValidData(user: User): Boolean{
val firstName: String = user.firstName ?: return false
val lastName = user.lastName ?: return false
return firstName.isNotBlank() && lastName.isNotBlank()
}Why is it possible to assign return to a varialbe?
Kotlin type system
In Kotlin almost everything is an expression.
val name = when (number) {
1 -> "one"
2 -> "two"
}Kotlin type system
In Kotlin almost everything is an expression.
val name = when (number) {
1 -> "one"
2 -> "two"
}val message = if (number % 2) "even" else "odd"Kotlin type system
In Kotlin almost everything is an expression.
val function = fun (param: String){
//do stuff
}val name = when (number) {
1 -> "one"
2 -> "two"
}val message = if (number % 2) "even" else "odd"Kotlin type system
data class User (
val firstName: String?,
val lastName: String?
)
fun hasValidData(user: User): Boolean{
val firstName: String = user.firstName ?: return false
val lastName = user.lastName ?: return false
return firstName.isNotBlank() && lastName.isNotBlank()
}Why is it possible to assign return to a varialbe?
Kotlin type system
data class User (
val firstName: String?,
val lastName: String?
)
fun hasValidData(user: User): Boolean{
val firstName: String = user.firstName ?: return false
val lastName = user.lastName ?: return false
return firstName.isNotBlank() && lastName.isNotBlank()
}Kotlin type system
returns Nothing
Why is it possible to assign return to a varialbe?
data class User (
val firstName: String?,
val lastName: String?
)
fun hasValidData(user: User): Boolean{
val firstName: String = user.firstName ?: return false
val lastName = user.lastName ?: return false
return firstName.isNotBlank() && lastName.isNotBlank()
}Because Nothing is subtype of everything
Kotlin type system
Liskov Substitution Principle
If S is subtype of T, then objects of type T may be replaced with objects of type S without altering any of the desirable properties of that program.
data class User (
val firstName: String?,
val lastName: String?
)
fun hasValidData(user: User): Boolean{
val firstName: String = return false
val lastName = user.lastName ?: return false
return firstName.isNotBlank() && lastName.isNotBlank()
}Kotlin type system
data class User (
val firstName: String?,
val lastName: String?
)
fun hasValidData(user: User): Boolean{
val firstName: String = return false
val lastName = user.lastName ?: return false
return firstName.isNotBlank() && lastName.isNotBlank()
}possible but useless
Kotlin type system
data class User (
val firstName: String?,
val lastName: String?
)
fun hasValidData(user: User): Boolean{
val firstName: String = return false
val lastName = user.lastName ?: return false
return firstName.isNotBlank() && lastName.isNotBlank()
}possible but useless
Kotlin type system
Warning: Unreachable code
data class User (
val firstName: String?,
val lastName: String?
)
fun hasValidData(user: User): Boolean{
val firstName = user.firstName ?: throw RunTimeException()
val lastName = user.lastName ?: return false
return firstName.isNotBlank() && lastName.isNotBlank()
}Throw returns Nothing too.
Kotlin type system
fun test(): String?{
TODO()
return null
}Warning: Unreachable code
public inline fun TODO(): Nothing = throw NotImplementedError()Kotlin type system
fun test(): String?{
TODO()
return null
}Warning: Unreachable code
The compiler knows after Nothing is returned, the execution flow stops.
public inline fun TODO(): Nothing = throw NotImplementedError()Kotlin type system
So this will actually never be assigned,
because the function ends with the return statement.
data class User (
val firstName: String?,
val lastName: String?
)
fun hasValidData(user: User): Boolean{
val firstName: String = user.firstName ?: return false
val lastName = user.lastName ?: return false
return firstName.isNotBlank() && lastName.isNotBlank()
}Kotlin type system
Kotlin vs Java
Kotlin value assignment (a = 1) is not an expression in Kotlin, while it is in Java because over there it returns assigned value (in Java you can do
a = b = 2
or
a = 2 * (b = 3))
Kotlin vs Java
This helps avoid confusion between comparisons and assignments, which is a common source of mistakes in languages that treat them as expressions, such as Java or C/C++.
Kotlin vs Java
All usages of control structures (if, switch) in Java are not expressions, while Kotlin allowed if, when and try to return values:
val bigger = if(a > b) a else b
val color = when {
relax -> GREEN
studyTime -> YELLOW
else -> BLUE
}
val object = try {
gson.fromJson(json)
} catch (e: Throwable) {
null
}Kotlin vs Java
Kotlin vs Java
In java primitive types aren’t part of the hierarchy.
Kotlin vs Java
In java primitive types aren’t part of the hierarchy.
That means you have to use wrapper types such as java.lang.Integer to represent a primitive type value when Object is required. In Kotlin, Any is a supertype of all types, including the primitive types such as Int.
Kotlin vs Java
All Kotlin classes have the following three methods: toString, equals, and hashCode. These methods are inherited from Any. Other methods defined on java.lang.Object (such as wait and notify) aren’t available on Any, but you can call them if you manually cast the value to java.lang.Object.
Kotlin vs Java
What distinguishes Kotlin’s Unit from Java’s void? Unit is a full-fledged type, and, unlike void, it can be used as a type argument. Only one value of this type exists; it’s also called Unit and is returned implicitly.
Kotlin vs Java
This is useful when you override a function that returns a generic parameter and make it return a value of the Unit type.
Kotlin vs Java
This is useful when you override a function that returns a generic parameter and make it return a value of the Unit type.
interface Processor{
fun process(): T
}
class NoResultProcessor: Processor{
override fun process(){
// do stuff
}
}Kotlin vs Java
Kotlin doesn’t automatically convert numbers from one type to another, even when the type you’re assigning your value to is larger and could comfortably hold the value you’re trying to assign.
Kotlin vs Java
Kotlin doesn’t automatically convert numbers from one type to another, even when the type you’re assigning your value to is larger and could comfortably hold the value you’re trying to assign.
byte b = 4;
short s = b;
int x = s;
long l = x;
float f = l;
double y = f;Kotlin vs Java
Kotlin doesn’t automatically convert numbers from one type to another, even when the type you’re assigning your value to is larger and could comfortably hold the value you’re trying to assign.
byte b = 4;
short s = b;
int x = s;
long l = x;
float f = l;
double y = f;val i = 1
val l: Long = i // Error: type mismatchInteger type widening
Integer type widening
fun foo(value: Int) = 1
fun foo(value: Short) = 2Integer type widening
fun foo(value: Int) = 1
fun foo(value: Short) = 2foo(2)Integer type widening
fun foo(value: Long) = 1
fun foo(value: Short) = 2foo(2)Integer type widening
fun foo(value: Long) = 1
fun foo(value: Short) = 2foo(2)Overload resolution ambiguity. All these functions match ...
Integer type widening
fun foo(value: Long) = 1foo(2)What I did not cover:
- Platform types
- Covariance and contravariance
- Unsigned number types
What I did not cover:
- Platform types
- Covariance and contravariance
- Unsigned number types
- Union types with errors
https://www.linkedin.com/in/ali-ahmadabadiha-59690923b/
resources:
https://www.linkslist.app/Xhs6khK


Video of this presentation is available at:
https://www.youtube.com/watch?v=5NoPe1__OcA
Code
By Ali Ahmadabadiha
Code
- 144