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
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
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
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
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
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
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
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
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
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
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
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
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
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
val / var x: Type? : T(x) = Type U Nothing? Statement: T in (x) T out (x) If: T in (x) T true (x), T false (x) Merge: T in1 (x), T in2 (x) T out (x) Kotlin: from null dereference to smart casts 21
T true (x) = T in (x) \ {Nothing?} T false (x) = T in (x) & {Nothing?} if (x is Something) T true (x) = T in (x) & {Something} T false (x) = T in (x) \ {Something} if (x == y) T true (x,y) = T in (x) & T in (y) T false (x) = T in (x) \ T in (y) T false (y) = T in (y) \ T in (x) Kotlin: from null dereference to smart casts 22
FalseA U FalseB if (A || B) True: TrueA U TrueB False: FalseA & FalseB Example: if (x == null && y != null) T true (x) = T in (x) & {Nothing?} T true (y) = T in (y) \ {Nothing?} T false (x) = T in (x) T false (y) = T in (y) Kotlin: from null dereference to smart casts 23
{Nothing?} x as Something T out (x) = T in (x) & {Something} x?.foo(...) T foo (x) = T in (x) \ {Nothing?} T out (x) = T in (x) Kotlin: from null dereference to smart casts 24
y ◦ T out (x) = T in (y) Initialization with given type: var x: Type = y ◦ T out (x) = { Type } Before entering a loop ◦ For all X changed inside: T out (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