Slide 1

Slide 1 text

Mikhail Glukhikh mailto: [email protected] JetBrains, Senior Software Developer

Slide 2

Slide 2 text

 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

Slide 3

Slide 3 text

 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

Slide 4

Slide 4 text

 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

Slide 5

Slide 5 text

 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

Slide 6

Slide 6 text

fun main(args: Array) { 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

Slide 7

Slide 7 text

 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): 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

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

fun String.greet() = println("Hello, $this") fun greet(args: List) = args.filter { it.isNotEmpty() } .sortBy { it } .forEach { it.greet() } Kotlin: from null dereference to smart casts 9

Slide 10

Slide 10 text

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

Slide 11

Slide 11 text

 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

Slide 12

Slide 12 text

 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

Slide 13

Slide 13 text

 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

Slide 14

Slide 14 text

 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

Slide 15

Slide 15 text

 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

Slide 16

Slide 16 text

 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

Slide 17

Slide 17 text

 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

Slide 18

Slide 18 text

 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

Slide 19

Slide 19 text

 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

Slide 20

Slide 20 text

 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

Slide 21

Slide 21 text

 val / var x: Type : T(x) = Type  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

Slide 22

Slide 22 text

 if (x != null) or while (x != null) 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

Slide 23

Slide 23 text

 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) 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

Slide 24

Slide 24 text

 x!! T out (x) = T in (x) \ {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

Slide 25

Slide 25 text

 if (…) { … } else { … } Out = In1 U In2  when (…) { … -> …; … -> …; else -> …;} Out = In1 U In2 U … U In(else) Kotlin: from null dereference to smart casts 25

Slide 26

Slide 26 text

 Assignment: x = y or initialization: var x = 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

Slide 27

Slide 27 text

 Classic data flow analysis on CFG ◦ Variable initialization analysis ◦ Variable usage analysis ◦ Code reachability analysis ◦ … Kotlin: from null dereference to smart casts 27

Slide 28

Slide 28 text

 Total smart casts: 8500  Unsafe operations ◦ !! : 1500 (mostly provoked by implicit conventions) ◦ as : 1500  Checks: ◦ != null : 2000 ◦ == null : 1000  Safe operations: ◦ ?. : 2500 ◦ as? : 1000 ◦ ?: : 2500 Kotlin: from null dereference to smart casts 28

Slide 29

Slide 29 text

 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

Slide 30

Slide 30 text

 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

Slide 31

Slide 31 text

 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

Slide 32

Slide 32 text

 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