Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Bulletproofing your foot for Kotlin

Bulletproofing your foot for Kotlin

A brief tour of some of the more outstanding features of Kotlin, highlighting the caveats of certain features and flaws that will have you scratching your head for hours.

Enrique Zamudio

November 16, 2017
Tweet

More Decks by Enrique Zamudio

Other Decks in Programming

Transcript

  1. Who? • Programming for a living since 1994 • Doing

    Java since 2000 • Experience in Java, C, C#, Objective-C, Groovy, Scala • Worked on Ceylon compiler 2012-2017 • Became Java Champion in 2015 #Hashtag @chochosmx
  2. Kotlin • Created by JetBrains • Static typing • Not

    Java! • Official Android support • JVM, Javascript #Hashtag @twitter
  3. Nice features • Data classes • Destructuring • Lambdas, higher

    order functions, function refs, method refs • Top-level methods • Declaration-site variance • Type inference • "Typesafe null" • String interpolation #Hashtag @twitter
  4. THE GOOD PARTS: DATA CLASSES data class Person(val name:String, val

    birthDate:Date) •toString() and equals() automagically added •no hashCode() though
  5. THE GOOD PARTS: DESTRUCTURING val p = Person("John Doe", today)

    val (n, f) = p val map = mapOf(1 to "one", 2 to "two") for ((k, v) in map) { ... }
  6. THE GOOD PARTS: FUNCTIONS fun foo() { ... } fun

    bar(f:() -> (Unit)) = f() bar(::foo) bar( { println("baz") } )
  7. THE GOOD PARTS: STRING INTERPOLATION val p = Person("John Doe",

    today) val (n, f) = p println("Name: $n birth: ${p.birthDate}")
  8. THE GOOD PARTS: TYPE INFERENCE val p = "hello" fun

    foo(bar:String) = bar.length fun foo(bar:String) { return bar.length }
  9. THE GOOD PARTS: SMART CASTS val p:Any = "string" if

    (p is String) { println(p.toUpperCase()) }
  10. NOT SO GOOD: STILL HAVE CASTS val p:Any = 1

    if (p is Int) { println((p as String).toUpperCase()) }
  11. THE GOOD PARTS: TYPESAFE NULL var p = "hello" p

    = null var p:String? = "hello" p = null
  12. THE GOOD PARTS: TYPESAFE NULL var x:String? = "hello" fun

    foo(s:String) {...} foo(x) //COMPILER ERROR if (x != null) { foo(x) }
  13. NOT GOOD: TYPESAFE NULL KILLSWITCH var x:String? = "hello" fun

    foo(s:String) {...} foo(x!!) //RUNTIME ERROR
  14. NOT GOOD: TYPESAFE NULL KILLSWITCH fun foo(s:String?) { println(s?.length) }

    foo(x?:"") fun bar(s:String?) { println(s!!.length) } foo(x!!) ✔ ✘
  15. GOOD: OPERATOR OVERLOADING class Foo(val x:Int) { operator fun plus(o:Foo)

    = Foo(o.x + x) operator fun times(o:Foo) = Foo(o.x * x) }
  16. GOOD: OPERATOR OVERLOADING val a = Foo(1) val b =

    Foo(2) println(a + b) println(a * b) println(a.plus(b)) println(a.times(b))
  17. NOT SO GOOD: INFORMAL OPERATOR OVERLOADING ➤ No interfaces to

    define behavior ➤ Could have used static typing here class Foo(val x:Int) { operator fun plus(o:Foo) = Foo(x+o.x) fun plus(i:Int) = x+i } println(Foo(1)+1)
  18. GOOD: EXTENSION METHODS data class Person(val name:String, val birthDate:Date) fun

    Person.debug() { println("I'm $name born on $birthDate") }
  19. NOT SO GOOD: EXTENSION OPERATORS data class Person(val name:String, val

    birthDate:Date) operator fun Person.plus(other:Person) { ???? }
  20. REALLY NOT GOOD: NONLOCAL RETURN fun foo() { listOf(1, 2,

    3).forEach { println(it) if (it > 0) { return } } println("All done!") }