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

Kotlin’s Mind Blowers

Kotlin’s Mind Blowers

A curated collection of authentic “ohhhhh”, “can’t believe it works”, and “WAIT YOU CAN DO THAT” experiences, evoked by some of the most disruptive properties of the Kotlin language, slowly refined through an artisanal all-natural process. [ gluten free / may contain traces of nuts ]

Presented at Kotlin Night Berlin 2018
https://www.meetup.com/kotlin-berlin/events/247865835/

--> Second part: https://bit.ly/kotlin-mind-blowers2

Eugenio Marletti

March 15, 2018
Tweet

More Decks by Eugenio Marletti

Other Decks in Technology

Transcript

  1. Kotlin’s
    Mind
    Blowers
    Eugenio Marletti
    @workingkills

    View Slide

  2. View Slide

  3. View Slide

  4. @Deprecated("Just don't.")
    fun deprecatedFun(age: Int, name: String) {
    !" nasty stuff
    }
    data class Name(val name: String)
    data class Age(val age: Int)
    fun niceFun(name: Name, age: Age) {
    !" good stuff
    }
    fun usage(myName: String, myAge: Int) {
    !" ⚠ 'deprecatedFun(Int, String): Unit' is deprecated. Just Don't.
    deprecatedFun(myAge, myName)
    }

    View Slide

  5. @Deprecated("Just don't.", level = DeprecationLevel.WARNING)
    fun deprecatedFun(age: Int, name: String) {
    !" nasty stuff
    }
    data class Name(val name: String)
    data class Age(val age: Int)
    fun niceFun(name: Name, age: Age) {
    !" good stuff
    }
    fun usage(myName: String, myAge: Int) {
    !" ⚠ 'deprecatedFun(Int, String): Unit' is deprecated. Just Don't.
    deprecatedFun(myAge, myName)
    }

    View Slide

  6. @Deprecated("Just don't.", level = DeprecationLevel.ERROR)
    fun deprecatedFun(age: Int, name: String) {
    !" nasty stuff
    }
    data class Name(val name: String)
    data class Age(val age: Int)
    fun niceFun(name: Name, age: Age) {
    !" good stuff
    }
    fun usage(myName: String, myAge: Int) {
    !" ❌ Using 'deprecatedFun(Int, String): Unit' is an error. Just Don't.
    deprecatedFun(myAge, myName)
    }

    View Slide

  7. @Deprecated("Just don't.", level = DeprecationLevel.HIDDEN)
    fun deprecatedFun(age: Int, name: String) {
    !" nasty stuff
    }
    data class Name(val name: String)
    data class Age(val age: Int)
    fun niceFun(name: Name, age: Age) {
    !" good stuff
    }
    fun usage(myName: String, myAge: Int) {
    !" ❌ Unresolved reference: deprecatedFun
    deprecatedFun(myAge, myName)
    }

    View Slide

  8. @Deprecated("Just don't.", ReplaceWith("niceFun(Name(name), Age(age))"))
    fun deprecatedFun(age: Int, name: String) {
    !" nasty stuff
    }
    data class Name(val name: String)
    data class Age(val age: Int)
    fun niceFun(name: Name, age: Age) {
    !" good stuff
    }
    fun usage(myName: String, myAge: Int) {
    !" #
    deprecatedFun(myAge, myName)
    }

    View Slide

  9. @Deprecated("Just don't.", ReplaceWith("niceFun(Name(name), Age(age))"))
    fun deprecatedFun(age: Int, name: String) {
    !" nasty stuff
    }
    data class Name(val name: String)
    data class Age(val age: Int)
    fun niceFun(name: Name, age: Age) {
    !" good stuff
    }
    fun usage(myName: String, myAge: Int) {
    !" #
    deprecatedFun(myAge, myName)
    }

    View Slide

  10. @Deprecated("Just don't.", ReplaceWith("niceFun(Name(name), Age(age))"))
    fun deprecatedFun(age: Int, name: String) {
    !" nasty stuff
    }
    data class Name(val name: String)
    data class Age(val age: Int)
    fun niceFun(name: Name, age: Age) {
    !" good stuff
    }
    fun usage(myName: String, myAge: Int) {
    !" #
    deprecatedFun(myAge, myName)
    }

    View Slide

  11. @Deprecated("Just don't.", ReplaceWith("niceFun(Name(name), Age(age))"))
    fun deprecatedFun(age: Int, name: String) {
    !" nasty stuff
    }
    data class Name(val name: String)
    data class Age(val age: Int)
    fun niceFun(name: Name, age: Age) {
    !" good stuff
    }
    fun usage(myName: String, myAge: Int) {
    !" ✅
    niceFun(Name(myName), Age(myAge))
    }

    View Slide

  12. typealias TotallyNotThatClass = ThatClass

    View Slide

  13. typealias AbsSubject = Subject

    View Slide

  14. class BoringClass {
    fun washDishes() = "maybe later"
    }
    fun usage() {
    BoringClass().washDishes()
    }

    View Slide

  15. class ExcitingClass {
    fun washDishes() = "maybe later"
    }
    fun usage() {
    BoringClass().washDishes()
    }

    View Slide

  16. class ExcitingClass {
    fun washDishes() = "maybe later"
    }
    fun usage() {
    !" ❌ Unresolved reference: BoringClass
    BoringClass().washDishes()
    }

    View Slide

  17. @Deprecated("Stop being boring.")
    typealias BoringClass = ExcitingClass
    class ExcitingClass {
    fun washDishes() = "maybe later"
    }
    fun usage() {
    !" ⚠ 'typealias BoringClass = ExcitingClass' is deprecated.
    !" Stop being boring.
    BoringClass().washDishes()
    }

    View Slide

  18. @Deprecated("Stop being boring.", ReplaceWith("ExcitingClass"))
    typealias BoringClass = ExcitingClass
    class ExcitingClass {
    fun washDishes() = "maybe later"
    }
    fun usage() {
    !" ⚠ 'typealias BoringClass = ExcitingClass' is deprecated.
    !" Stop being boring.
    BoringClass().washDishes()
    }

    View Slide

  19. package first
    fun topLevelFunction(i: Int) = i
    fun topLevelFunction(s: String) = s

    View Slide

  20. package first
    fun topLevelFunction(i: Int) = i
    fun topLevelFunction(s: String) = s
    -----------------------------------
    package second
    import first.topLevelFunction

    View Slide

  21. package my.package
    data class ColorInt(val color: Int)

    View Slide

  22. package my.package
    import android.support.annotation.ColorInt
    data class ColorInt(@ColorInt val color: Int)

    View Slide

  23. package my.package
    import android.support.annotation.ColorInt
    data class ColorInt(@ColorInt val color: Int)
    ---------------------------------------------
    package not.my.package
    !" ❌ Conflicting import, imported name 'ColorInt' is ambiguous
    import android.support.annotation.ColorInt
    import my.package.ColorInt

    View Slide

  24. package my.package
    import android.support.annotation.ColorInt
    data class ColorInt(@ColorInt val color: Int)
    ---------------------------------------------
    package not.my.package
    !" ✅
    import android.support.annotation.ColorInt as ColorIntAnnotation
    import my.package.ColorInt

    View Slide

  25. package my.package
    import android.support.annotation.ColorInt
    data class ColorInt(@ColorInt val color: Int)
    ---------------------------------------------
    package not.my.package
    !" ✅
    import android.support.annotation.ColorInt as ColorIntAnnotationDuplicate
    import android.support.annotation.ColorInt as ColorIntAnnotation
    import my.package.ColorInt

    View Slide

  26. fun oppaFunctionalStyle(list: List) =
    list.map {
    it.toCharArray().map {
    if (it.isDigit())
    return@map CharArray(0) !" which map? %
    else
    it.toUpperCase()
    }
    }

    View Slide

  27. fun oppaFunctionalStyle(list: List) =
    list.map listMap@ {
    it.toCharArray().map charMap@ {
    if (it.isDigit())
    return@listMap CharArray(0) !" that map! &
    else
    it.toUpperCase()
    }
    }

    View Slide

  28. fun stringLengthOrNull(maybeString: Any?) =
    if (maybeString is String)
    maybeString.length
    else
    null

    View Slide

  29. fun stringLengthOrNull(maybeString: Any?) =
    (maybeString as? String)!#length

    View Slide

  30. fun printEverything(vararg args: String) {
    println(args)
    }
    fun usage(stringArray: Array) {
    printEverything(*stringArray)
    }

    View Slide

  31. fun printEverything(vararg args: String) {
    println(args)
    }
    fun usage(
    singleString: String,
    anotherSingleString: String,
    stringArray: Array,
    anotherStringArray: Array) {
    printEverything(*stringArray)
    }

    View Slide

  32. fun printEverything(vararg args: String) {
    println(args)
    }
    fun usage(
    singleString: String,
    anotherSingleString: String,
    stringArray: Array,
    anotherStringArray: Array) {
    printEverything(
    singleString,
    *stringArray,
    anotherSingleString,
    *anotherStringArray)
    }

    View Slide

  33. fun veryDescriptiveFun(
    arg1: String,
    arg2: Int,
    arg3: Int,
    arg4: Boolean
    ) = "meh"

    View Slide

  34. fun veryDescriptiveFun(
    arg1: String,
    arg2: Int = arg1.length,
    arg3: Int = arg2,
    arg4: Boolean
    ) = "cool"

    View Slide

  35. fun veryDescriptiveFun(
    arg1: String,
    arg2: Int = arg1.length,
    arg3: Int = arg2,
    arg4: Boolean = loadEntireDbInMemory()!#isEmpty() !& areYouSure()
    ) = "oh no"

    View Slide

  36. fun iterate(iterable: Iterable) {
    iterable
    .onEach { println(it) }
    .map { it.length }
    .forEach { println(it) }
    }
    fun sequentiate(sequence: Sequence) {
    sequence
    .onEach { println(it) }
    .map { it.length }
    .forEach { println(it) }
    }
    fun usage() {
    val strings = listOf("a", "bb", "ccc")
    iterate(strings.asIterable())
    sequentiate(strings.asSequence())
    }

    View Slide

  37. fun iterate(iterable: Iterable) { !"
    iterable !"
    .onEach { println(it) } !"
    .map { it.length } !"
    .forEach { println(it) } !"
    } !"
    fun sequentiate(sequence: Sequence) { !"
    sequence !"
    .onEach { println(it) } !"
    .map { it.length } !"
    .forEach { println(it) } !"
    } !"
    fun usage() {
    val strings = listOf("a", "bb", "ccc")
    iterate(strings.asIterable())
    sequentiate(strings.asSequence())
    }

    View Slide

  38. fun iterate(iterable: Iterable) { !" a
    iterable !" bb
    .onEach { println(it) } !" ccc
    .map { it.length } !" 1
    .forEach { println(it) } !" 2
    } !" 3
    fun sequentiate(sequence: Sequence) { !"
    sequence !"
    .onEach { println(it) } !"
    .map { it.length } !"
    .forEach { println(it) } !"
    } !"
    fun usage() {
    val strings = listOf("a", "bb", "ccc")
    iterate(strings.asIterable())
    sequentiate(strings.asSequence())
    }

    View Slide

  39. fun iterate(iterable: Iterable) { !" a
    iterable !" bb
    .onEach { println(it) } !" ccc
    .map { it.length } !" 1
    .forEach { println(it) } !" 2
    } !" 3
    fun sequentiate(sequence: Sequence) { !" a
    sequence !" 1
    .onEach { println(it) } !" bb
    .map { it.length } !" 2
    .forEach { println(it) } !" ccc
    } !" 3
    fun usage() {
    val strings = listOf("a", "bb", "ccc")
    iterate(strings.asIterable())
    sequentiate(strings.asSequence())
    }

    View Slide

  40. void

    View Slide

  41. void !" not a type

    View Slide

  42. void !' Unit

    View Slide

  43. void !' Unit
    “In type theory, a unit type is a type that allows only one value.”

    View Slide

  44. void !' Unit !" single instance

    View Slide

  45. fun unity() { }

    View Slide

  46. fun unity(): Unit { }

    View Slide

  47. fun unity() = Unit

    View Slide

  48. fun unity() = println("sweet")

    View Slide

  49. fun unity() = java.lang.System.out.println("sweet")

    View Slide

  50. Void

    View Slide

  51. Void !" a type that can’t be instantiated

    View Slide

  52. Void !' Nothing

    View Slide

  53. Void !' Nothing
    “In type theory, the bottom type is the type that has no values.”
    bottom
    zero
    empty

    View Slide

  54. Void !' Nothing !" a type that can’t be instantiated (same!)

    View Slide

  55. Void !' Nothing?

    View Slide

  56. fun foreverNull(): Nothing? = null

    View Slide

  57. fun inifinite() {
    while (true) {
    !" nap
    }
    }
    fun naive() {
    inifinite()
    !" always believe in yourself!⚠
    println("I've achieved all my hopes and dreams!")
    }

    View Slide

  58. fun inifinite(): Nothing {
    while (true) {
    !" nap
    }
    }
    fun naive() {
    inifinite()
    !" ⚠ Unreachable code
    println("I've achieved all my hopes and dreams!")
    }

    View Slide

  59. fun fiveMoreMinutesPlease(): VeryComplexType

    View Slide

  60. fun fiveMoreMinutesPlease(): VeryComplexType = TODO()

    View Slide

  61. fun fiveMoreMinutesPlease(): VeryComplexType = TODO()
    fun TODO(): Nothing = throw NotImplementedError()

    View Slide

  62. data class Person(
    val name: String,
    val age: Int,
    val likesDataClasses: Boolean)

    View Slide

  63. data class Person(
    val name: String,
    val age: Int,
    val likesDataClasses: Boolean)
    fun parsePerson(map: Map): Person? {
    val name = map["name"]
    if (name is String) {
    val age = map["age"]
    if (age is Int) {
    val likesDataClasses = map["likes-data-classes"]
    if (likesDataClasses is Boolean) {
    return Person(
    name,
    age,
    likesDataClasses)
    }
    }
    }
    return null
    }

    View Slide

  64. data class Person(
    val name: String,
    val age: Int,
    val likesDataClasses: Boolean)
    fun parsePerson(map: Map): Person? {
    val name = map["name"]
    if (name !is String) return null
    val age = map["age"]
    if (age !is Int) return null
    val likesDataClasses = map["likes-data-classes"]
    if (likesDataClasses !is Boolean) return null
    return Person(
    name,
    age,
    likesDataClasses)
    }

    View Slide

  65. data class Person(
    val name: String,
    val age: Int,
    val likesDataClasses: Boolean)
    fun parsePerson(map: Map): Person? {
    val name = map["name"] as? String !& return null
    val age = map["age"] as? Int !& return null
    val likesDataClasses = map["likes-data-classes"] as? Boolean !& return null
    return Person(
    name,
    age,
    likesDataClasses)
    }

    View Slide

  66. data class Person(
    val name: String,
    val age: Int,
    val likesDataClasses: Boolean)
    fun parsePerson(map: Map): Person? {
    return Person(
    map["name"] as? String !& return null,
    map["age"] as? Int !& return null,
    map["likes-data-classes"] as? Boolean !& return null)
    }

    View Slide

  67. !" Elvis operator
    !&

    View Slide

  68. !&
    "hey"

    View Slide

  69. a += b a.plusAssign(b)
    a -= b a.minusAssign(b)
    a!* a.inc()
    a!, a.dec()
    a + b a.plus(b)
    a - b a.minus(b)
    a * b a.times(b)
    a / b a.div(b)
    a % b a.rem(b)
    a!-b a.rangeTo(b)
    +a a.unaryPlus()
    -a a.unaryMinus()
    !a a.not()

    View Slide

  70. a[i] a.get(i)
    a[i_1, !!., i_n] a.get(i_1, !!., i_n)
    a += b a.plusAssign(b)
    a -= b a.minusAssign(b)
    a *= b a.timesAssign(b)
    a !/ b a.divAssign(b)
    a %= b a.remAssign(b)
    a!* a.inc()
    a!, a.dec()
    a + b a.plus(b)
    a - b a.minus(b)
    a * b a.times(b)
    a / b a.div(b)
    a % b a.rem(b)
    a!-b a.rangeTo(b)
    +a a.unaryPlus()
    -a a.unaryMinus()
    !a a.not()

    View Slide

  71. a > b a.compareTo(b) > 0
    a < b a.compareTo(b) < 0
    a !0 b a.compareTo(b) !0 0
    a !1 b a.compareTo(b) !1 0
    a[i] a.get(i)
    a[i_1, !!., i_n] a.get(i_1, !!., i_n)
    a[i] = b a.set(i, b)
    a[i_1, !!., i_n] = b a.set(i_1, !!., i_n, b)
    a += b a.plusAssign(b)
    a -= b a.minusAssign(b)
    a *= b a.timesAssign(b)
    a !/ b a.divAssign(b)
    a %= b a.remAssign(b)
    a!* a.inc()
    a!, a.dec()
    a + b a.plus(b)
    a - b a.minus(b)
    a * b a.times(b)
    a / b a.div(b)
    a % b a.rem(b)
    a!-b a.rangeTo(b)
    !a a.not()

    View Slide

  72. a() a.invoke()
    a(i) a.invoke(i)
    a in b b.contains(a)
    a !in b !b.contains(a)
    a > b a.compareTo(b) > 0
    a < b a.compareTo(b) < 0
    a !0 b a.compareTo(b) !0 0
    a !1 b a.compareTo(b) !1 0
    a[i] a.get(i)
    a[i_1, !!., i_n] a.get(i_1, !!., i_n)
    a[i] = b a.set(i, b)
    a[i_1, !!., i_n] = b a.set(i_1, !!., i_n, b)
    a += b a.plusAssign(b)
    a -= b a.minusAssign(b)
    a *= b a.timesAssign(b)
    a !/ b a.divAssign(b)
    a %= b a.remAssign(b)
    a - b a.minus(b)
    a * b a.times(b)
    a / b a.div(b)
    a % b a.rem(b)
    a!-b a.rangeTo(b)

    View Slide

  73. a() a.invoke()
    a(i) a.invoke(i)
    a(i_1, !!., i_n) a.invoke(i_1, !!., i_n)
    a in b b.contains(a)
    a !in b !b.contains(a)
    a > b a.compareTo(b) > 0
    a < b a.compareTo(b) < 0
    a !0 b a.compareTo(b) !0 0
    a !1 b a.compareTo(b) !1 0
    a[i] a.get(i)
    a[i_1, !!., i_n] a.get(i_1, !!., i_n)
    a[i] = b a.set(i, b)
    a[i_1, !!., i_n] = b a.set(i_1, !!., i_n, b)
    a += b a.plusAssign(b)
    a -= b a.minusAssign(b)
    a *= b a.timesAssign(b)
    a !/ b a.divAssign(b)
    a %= b a.remAssign(b)

    View Slide

  74. a() a.invoke()
    a(i) a.invoke(i)
    a(i_1, !!., i_n) a.invoke(i_1, !!., i_n)
    a in b b.contains(a)
    a !in b !b.contains(a)
    a > b a.compareTo(b) > 0
    a < b a.compareTo(b) < 0
    a !0 b a.compareTo(b) !0 0
    a !1 b a.compareTo(b) !1 0
    a[i] a.get(i)
    a[i_1, !!., i_n] a.get(i_1, !!., i_n)
    a[i] = b a.set(i, b)
    a[i_1, !!., i_n] = b a.set(i_1, !!., i_n, b)
    a %= b a.remAssign(b)

    View Slide

  75. a() a.invoke()
    a(i) a.invoke(i)
    a(i_1, !!., i_n) a.invoke(i_1, !!., i_n)
    a in b b.contains(a)
    a !in b !b.contains(a)
    a > b a.compareTo(b) > 0
    a < b a.compareTo(b) < 0
    a !0 b a.compareTo(b) !0 0
    a !1 b a.compareTo(b) !1 0
    a[i_1, !!., i_n] a.get(i_1, !!., i_n)
    a[i] = b a.set(i, b)
    a[i_1, !!., i_n] = b a.set(i_1, !!., i_n, b)

    View Slide

  76. getValue, setValue, provideDelegate
    val someValue by lazy { "don't judge me" }

    View Slide

  77. View Slide

  78. View Slide

  79. Kotlin tools team lead @ JetBrains
    co-author of “Kotlin in Action”
    @intelliyole on Twitter
    “Dmitry Jemerov” in “real life”
    yole

    View Slide

  80. “ ”
    “ ”
    Kotlin tools team lead @ JetBrains
    co-author of “Kotlin in Action”
    @intelliyole on Twitter
    “Dmitry Jemerov” in “real life”
    yole

    View Slide

  81. bit.ly/kotlin-mind-blowers
    Eugenio Marletti
    @workingkills

    View Slide