This document discusses Kotlin, a statically typed programming language that targets the JVM and JavaScript. It was developed by JetBrains since 2011 and is now open-source. Kotlin is null-safe, object-oriented, and compatible with both Java and Scala. It provides features like type inference, higher-order functions, and extension functions while being simpler than Scala.
2. Developed by JetBrains since 2011
Open-Source since 2012
Targets JVM and JavaScript
◦ Java 6 / 7 / 8 / Android
Statically Typed
Object-Oriented
◦ + Functional features
◦ + Procedural features
Java- and Scala-Compatible
Plugins for IDEA and Eclipse
Kotlin: from null dereference to
smart casts 2
3. 14 minor releases passed in 2012 – 2015
1.0 beta released (Nov 2015)
1.0 coming soon
Lines of Code
◦ ~250 KLOC in Kotlin project itself
◦ ~250 KLOC in other JetBrains projects
◦ ~1000 KLOC in non-JetBrains projects on GitHub
Kotlin: from null dereference to
smart casts 3
4. Working in Kotlin project since March 2015
Before: author of various research static
analysis tools
Also: associate professor in SPbPU
Kotlin: from null dereference to
smart casts 4
5. Full Java interoperability
Safer than Java
◦ Null safety
◦ No raw types
◦ Invariant arrays
◦ Read-only collections
More concise and expressive than Java
◦ Type inference
◦ Higher-order functions (closures)
◦ Extension functions
◦ Class delegation
Compiler is at least as fast as Java
Simpler than Scala
Kotlin: from null dereference to
smart casts 5
6. fun main(args: Array<String>) {
val name = if (args.isNotEmpty()) args[0]
else "Kotlin"
println("Hello, $name")
}
val / var name : Type or = …
fun name(a: TypeA, b: TypeB): Type { … } or = …
Array<>, String
if … else … expressions
"Hello, $name" or even "Hello, ${my.name}"
Kotlin: from null dereference to
smart casts 6
7. No primitive types, everything is an object
◦ Standard classes Int, Long, Char, Boolean, String, etc.
◦ Unit as the single-value type
fun main(args: Array<String>): Unit { … }
◦ Nothing as the type that never exists
fun todo(): Nothing = throw AssertionError()
◦ null has the type of Nothing?
◦ Any as the very base type for everything (not-null)
fun equals(other: Any?): Boolean = …
Interfaces and classes
Nullable and not-null types
◦ E.g. String? and String, Any? and Any, etc.
Kotlin: from null dereference to
smart casts 7
8. interface Food
interface Animal : Food {
enum class Kind { HERBIVORE,OMNIVORE,CARNIVORE }
val kind: Kind
fun eat(food: Food): Boolean
fun die() = println("It dies")
}
class Lion : Animal {
override val kind = Animal.Kind.CARNIVORE
override fun eat(food: Food) =
if (food is Animal) {
food.die()
true
} else false
}
}
Kotlin: from null dereference to
smart casts 8
9. fun String.greet() =
println("Hello, $this")
fun greet(args: List<String>) =
args.filter { it.isNotEmpty() }
.sortBy { it }
.forEach { it.greet() }
Kotlin: from null dereference to
smart casts 9
10. sealed class Tree {
object Empty: Tree()
class Leaf(val x: Int): Tree()
class Node(val left: Tree,
val right: Tree): Tree()
fun max(): Int = when (this) {
Empty -> Int.MIN_VALUE
is Leaf -> this.x
is Node -> Math.max(this.left.max(),
this.right.max())
}
}
Kotlin: from null dereference to
smart casts 10
11. Distinct nullable types Type? and
not-null types Type
Null checks and smart casts
fun foo(s: String?) {
// Error: Only safe or not-null asserted
// calls allowed
println(s.length)
// Ok, smart cast to String
if (s != null) println(s.length)
if (s == null) return
println(s.length) // Smart cast also here
}
Kotlin: from null dereference to
smart casts 11
12. Distinct nullable types Type? and
not-null types Type
Safe calls, not-null asserted calls
fun foo(s: String?) {
// Error: Only safe or not-null asserted
// calls allowed
println(s.length)
// Ok, safe call (s.length or null)
println(s?.length)
// Ok, not-null assertion (unsafe!)
println(s!!.length)
}
Kotlin: from null dereference to
smart casts 12
13. Distinct nullable types Type? and
not-null types Type
Safe call with Elvis operator
fun foo(s: String?) {
// Error: Only safe or
// not-null asserted calls allowed
println(s.length)
// Ok, safe call + Elvis (s.length or NOTHING)
println(s?.length ?: "NOTHING")
}
Kotlin: from null dereference to
smart casts 13
14. Flexible Types like Type!
◦ Type in Java Type! in Kotlin
◦ Type! is not a syntax, just notation
◦ Assignable to both Type and Type?
◦ Dot is applicable to a variable of Type!
◦ Annotations are taken into account
@NotNull Type in Java Type in Kotlin
Kotlin: from null dereference to
smart casts 14
15. is or !is to check, as or as? to convert
class StringHolder(val s: String) {
override fun equals(o: Any?): Boolean {
// Error: unresolved reference (o.s)
return s == o.s
if (o !is StringHolder) return false
// Ok, smart cast to StringHolder
return s == o.s
}
}
Kotlin: from null dereference to
smart casts 15
16. is or !is to check, as or as? to convert
class StringHolder(val s: String) {
override fun equals(o: Any?): Boolean {
// Ok, unsafe (ClassCastException)
return s == (o as StringHolder).s
// Ok, safe
return s == (o as? StringHolder)?.s
}
}
Kotlin: from null dereference to
smart casts 16
17. Top-down analysis on AST
For each relevant expression E, possible types of
E: T(E) are determined at each AST node
T(null) = Nothing?
Example
fun foo(s: String?) {
// T(s) = {String?} = {String,Nothing?}
if (s != null) {
// T(s) = {Nothing?}
println(s.length)
}
}
Kotlin: from null dereference to
smart casts 17
18. For local values, function parameters,
special this variable
For member or top-level values if:
◦ They are not overridable and have no custom getter AND
They are private or internal (not a part of public API) OR
They are protected or public, and used in the same
compilation module when declared
class My {
private val a: String? // safe
public val b: String? // same module only
internal open val c: String? // unsafe
private val d: String? // unsafe
get() = null
}
Kotlin: from null dereference to
smart casts 18
19. For local variables if
◦ a smart cast is performed not in the loop which changes the
variable after the smart cast
fun foo() {
var s: String? // T(s) = String U Nothing?
s = "abc" // T(s) = String
s.length // smart cast
while (s != "x") {
// Unsafe: changed later in the loop
if (s.length > 0) s = s.substring(1)
else s = null
}
}
Kotlin: from null dereference to
smart casts 19
20. For local variables if
◦ a smart cast is performed in the same function when the
variable is declared, not inside some closure
◦ no closure that changes the variable exists before the
location of the smart cast
fun indexOfMax(a: IntArray): Int? {
var maxI: Int? = null
a.forEachIndexed { i, value ->
if (maxI == null || value >= a[maxI]) {
maxI = i
}
}
return maxI
}
Kotlin: from null dereference to
smart casts 20
21. val / var x: Type :
T(x) = Type
val / var x: Type? :
T(x) = Type U Nothing?
Statement:
Tin(x) Tout(x)
If:
Tin(x) Ttrue(x), Tfalse(x)
Merge:
Tin1(x), Tin2(x) Tout(x)
Kotlin: from null dereference to
smart casts 21
22. if (x != null) or while (x != null)
Ttrue (x) = Tin(x) {Nothing?}
Tfalse(x) = Tin(x) & {Nothing?}
if (x is Something)
Ttrue (x) = Tin(x) & {Something}
Tfalse(x) = Tin(x) {Something}
if (x == y)
Ttrue (x,y) = Tin(x) & Tin(y)
Tfalse(x) = Tin(x) Tin(y)
Tfalse(y) = Tin(y) Tin(x)
Kotlin: from null dereference to
smart casts 22
23. if (A && B)
True: TrueA & TrueB
False: FalseA U FalseB
if (A || B)
True: TrueA U TrueB
False: FalseA & FalseB
Example: if (x == null && y != null)
Ttrue (x) = Tin(x) & {Nothing?}
Ttrue (y) = Tin(y) {Nothing?}
Tfalse(x) = Tin(x)
Tfalse(y) = Tin(y)
Kotlin: from null dereference to
smart casts 23
24. x!!
Tout(x) = Tin(x) {Nothing?}
x as Something
Tout(x) = Tin(x) & {Something}
x?.foo(...)
Tfoo(x) = Tin(x) {Nothing?}
Tout(x) = Tin(x)
Kotlin: from null dereference to
smart casts 24
25. if (…) { … } else { … }
Out = In1 U In2
when (…) { … -> …; … -> …; else -> …;}
Out = In1 U In2 U … U In(else)
Kotlin: from null dereference to
smart casts 25
26. Assignment: x = y or initialization: var x = y
◦ Tout(x) = Tin(y)
Initialization with given type: var x: Type = y
◦ Tout(x) = { Type }
Before entering a loop
◦ For all X changed inside: Tout(X) = Type(X)
data class Node(val s: String, val next: Node?)
fun foo(node: Node) {
var current: Node? // T = {Node,Nothing?}
current = node // T = {Node}
while (true) { // T = {Node,Nothing?}
println(current.s) // Error
if (current == null) break
println(current.s) // Ok: T = {Node}
current = current.next // T = {Node,Nothing?}
} // T = {Nothing?}
}
Kotlin: from null dereference to
smart casts 26
27. Classic data flow analysis on CFG
◦ Variable initialization analysis
◦ Variable usage analysis
◦ Code reachability analysis
◦ …
Kotlin: from null dereference to
smart casts 27
29. More precise loop analysis
More precise closure analysis
Extra helper annotations like
@Pure or @Consistent for mutable properties
…
Kotlin: from null dereference to
smart casts 29
30. http://kotlinlang.org – language information,
API reference, tutorials, koans, installation
instructions, community, etc.
http://github.com/JetBrains/Kotlin –
main compiler & plugin repository
http://blog.jetbrains.com/kotlin/ –
Kotlin blog
Questions?
Kotlin: from null dereference to
smart casts 30
31. Java Kotlin
◦ Checked exceptions
◦ Primitive types that are not classes
◦ Static members
◦ Non-private fields
Kotlin Java
◦ Extension functions
◦ Null-safety, smart casts
◦ String templates
◦ Properties
◦ Primary constructors
◦ Class delegation
◦ Type inference
◦ Singletons
◦ Operator overloading, infix functions
◦ …
Kotlin: from null dereference to
smart casts 31
32. Scala Kotlin
◦ Implicit conversions
◦ Overridable type members
◦ Existential types
◦ Structural types
◦ Value types
◦ Yield operator
◦ Actors
◦ …
Kotlin Scala
◦ Zero overhead null safety
◦ Smart casts
◦ Class delegation
Kotlin: from null dereference to
smart casts 32