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

Kotlin's Advanced Language Features

Kotlin's Advanced Language Features

Benoît Quenaudon

October 18, 2018
Tweet

More Decks by Benoît Quenaudon

Other Decks in Programming

Transcript

  1. Kotlin’s
    Advanced Language Features

    View Slide

  2. High Order Function's Extension

    View Slide

  3. fun String.blowUp() {
    boom()
    }
    "Nooooo".blowUp()

    View Slide

  4. fun buildString(
    builderAction: (StringBuilder) -> Unit
    ): String {a
    }b
    fun main(args: Array) {c
    }e

    View Slide

  5. fun buildString(
    builderAction: (StringBuilder) -> Unit
    ): String {a
    val sb = StringBuilder()
    builderAction(sb)
    return sb.toString()
    }b
    fun main(args: Array) {c
    }e

    View Slide

  6. fun buildString(
    builderAction: (StringBuilder) -> Unit
    ): String {a
    val sb = StringBuilder()
    builderAction(sb)
    return sb.toString()
    }b
    fun main(args: Array) {c
    val s = buildString({ stringBuilder ->
    stringBuilder.append("Hello, ")
    stringBuilder.append("World!")
    })d
    }e

    View Slide

  7. fun buildString(
    builderAction: (StringBuilder) -> Unit
    ): String {a
    val sb = StringBuilder()
    builderAction(sb)
    return sb.toString()
    }b
    fun main(args: Array) {c
    val s = buildString { stringBuilder ->
    stringBuilder.append("Hello, ")
    stringBuilder.append("World!")
    }d
    }e

    View Slide

  8. fun buildString(
    builderAction: (StringBuilder) -> Unit
    ): String {a
    val sb = StringBuilder()
    builderAction(sb)
    return sb.toString()
    }b
    fun main(args: Array) {c
    val s = buildString {
    it.append("Hello, ")
    it.append("World!")
    }d
    }e

    View Slide

  9. fun buildString(
    builderAction: (StringBuilder) -> Unit
    ): String {a
    val sb = StringBuilder()
    builderAction(sb)
    return sb.toString()
    }b
    fun main(args: Array) {c
    val s = buildString {
    append("Hello, ")
    append("World!")
    }d
    }e

    View Slide

  10. fun buildString(
    builderAction: StringBuilder.() -> Unit
    ): String {a
    val sb = StringBuilder()
    builderAction(sb)
    return sb.toString()
    }b
    fun main(args: Array) {c
    val s = buildString {
    append("Hello, ")
    append("World!")
    }d
    }e

    View Slide

  11. fun buildString(
    builderAction: StringBuilder.() -> Unit
    ): String {a
    val sb = StringBuilder()
    sb.builderAction()
    return sb.toString()
    }b
    fun main(args: Array) {c
    val s = buildString {
    append("Hello, ")
    append("World!")
    }d
    }e

    View Slide

  12. fun buildString(
    builderAction: StringBuilder.() -> Unit
    ): String {a
    val sb = StringBuilder()
    sb.builderAction()
    return sb.toString()
    }b
    fun main(args: Array) {c
    val s = buildString {
    append("Hello, ")
    append("World!")
    }d
    }e

    View Slide

  13. fun buildString(
    builderAction: StringBuilder.() -> Unit
    ): String {a
    val sb = StringBuilder()
    sb.builderAction()
    return sb.toString()
    }b
    fun main(args: Array) {c
    val s = buildString {
    this.append("Hello, ")
    append("World!")
    }d
    }e

    View Slide

  14. View Slide

  15. val taco = Taco()
    with(taco) {
    println(name)
    println(tasty)
    }

    View Slide

  16. fun with(
    receiver: T,
    block: T.() -> R
    ): R {
    return receiver.block()
    }

    View Slide

  17. When do we seal the casting?

    View Slide

  18. interface BinaryNumber
    object Zero : BinaryNumber
    object One : BinaryNumber

    View Slide

  19. interface BinaryNumber
    object Zero : BinaryNumber
    object One : BinaryNumber
    fun BinaryNumber.toInt():Int {a
    return when (this) {b
    is One -> 1
    is Zero -> 0
    else -> throw IllegalStateException()
    }c
    }d

    View Slide

  20. interface BinaryNumber
    object Zero : BinaryNumber
    object One : BinaryNumber
    fun BinaryNumber.toInt():Int {a
    return when (this) {b
    is One -> 1
    is Zero -> 0
    }c
    }d

    View Slide

  21. interface BinaryNumber
    object Zero : BinaryNumber
    object One : BinaryNumber
    fun BinaryNumber.toInt():Int {a
    return when (this) {b
    is One -> 1
    is Zero -> 0
    else -> throw IllegalStateException()
    }c
    }d

    View Slide

  22. interface BinaryNumber
    object Zero : BinaryNumber
    object One : BinaryNumber
    class Magic() : BinaryNumber() {
    fun abracadabra() {
    // ...
    }
    }
    fun BinaryNumber.toInt():Int {a
    return when (this) {b
    is One -> 1
    is Zero -> 0
    else -> throw IllegalStateException()
    }c
    }d

    View Slide

  23. interface BinaryNumber
    object Zero : BinaryNumber
    object One : BinaryNumber
    fun BinaryNumber.toInt():Int {a
    return when (this) {b
    is One -> 1
    is Zero -> 0
    else -> throw IllegalStateException()
    }c
    }d

    View Slide

  24. sealed class BinaryNumber
    object Zero : BinaryNumber()
    object One : BinaryNumber()
    fun BinaryNumber.toInt():Int {a
    return when (this) {b
    is One -> 1
    is Zero -> 0
    else -> throw IllegalStateException()
    }c
    }d

    View Slide

  25. sealed class BinaryNumber
    object Zero : BinaryNumber()
    object One : BinaryNumber()
    fun BinaryNumber.toInt():Int {a
    return when (this) {b
    is One -> 1
    is Zero -> 0
    }c
    }d

    View Slide

  26. sealed class BinaryNumber
    object Zero : BinaryNumber()
    object One : BinaryNumber()
    class Magic() : BinaryNumber() {z
    fun abracadabra() {w
    // ...
    }t
    }r
    fun BinaryNumber.toInt():Int {a
    return when (this) {b
    is One -> 1
    is Zero -> 0
    }c
    }d

    View Slide

  27. sealed class BinaryNumber
    object Zero : BinaryNumber()
    object One : BinaryNumber()
    class Magic() : BinaryNumber() {z
    fun abracadabra() {w
    // ...
    }t
    }r
    fun BinaryNumber.toInt():Int {a
    return when (this) {b
    is One -> 1
    is Zero -> 0
    }c
    }d

    View Slide

  28. sealed class BinaryNumber
    object Zero : BinaryNumber()
    object One : BinaryNumber()
    class Magic() : BinaryNumber() {z
    fun abracadabra() {w
    // ...
    }t
    }r
    fun BinaryNumber.toInt():Int {a
    return when (this) {b
    is One -> 1
    is Zero -> 0
    is Magic -> this.abracadabra()
    }c
    }d

    View Slide

  29. sealed class BinaryNumber
    object Zero : BinaryNumber()
    object One : BinaryNumber()
    class Magic() : BinaryNumber() {
    fun abracadabra() {
    // ...
    }
    }
    fun BinaryNumber.toInt():Int {a
    return when (this) {b
    is One -> 1
    is Zero -> 0
    is Magic -> this.abracadabra()
    }c
    }d

    View Slide

  30. View Slide

  31. fun requireNotNull(obj: Any?) {a
    if (obj == null) throw IllegalArgumentException()
    }d

    View Slide

  32. fun requireNotNull(obj: Any?) {a
    if (obj == null) throw IllegalArgumentException()
    }d
    fun foo(s: String?) {e
    requireNotNull(s)
    s.length
    }f

    View Slide

  33. fun requireNotNull(obj: Any?) {a
    contract { returns() implies (obj != null) }c
    if (obj == null) throw IllegalArgumentException()
    }d
    fun foo(s: String?) {e
    requireNotNull(s)
    s.length
    }f

    View Slide

  34. View Slide

  35. Error is Ever the Sequence of Haste

    View Slide

  36. people // List

    View Slide

  37. people // List
    .map(People::name)
    .filter { it.startsWith("J") }

    View Slide

  38. people // List
    .map(People::name) // List
    .filter { it.startsWith("J") } // List

    View Slide

  39. people // List
    .asSequence()
    .map(People::name)
    .filter { it.startsWith("J") }

    View Slide

  40. people // List
    .asSequence() // Sequence
    .map(People::name) // Sequence
    .filter { it.startsWith("J") } // Sequence

    View Slide

  41. people // List
    .asSequence() // Sequence
    .map(People::name) // Sequence
    .filter { it.startsWith("J") } // Sequence
    .toList() // List

    View Slide

  42. people
    .map(People::name)
    .find { it.startsWith("J") }

    View Slide

  43. people
    .map(People::name)
    .find { it.startsWith("J") }
    And Car Jes Wil Pir
    A C J W P
    A C J

    View Slide

  44. people.asSequence()
    .map(People::name)
    .find { it.startsWith("J") }
    And Car Jes Wil Pir
    A C J
    A C J

    View Slide

  45. View Slide

  46. Generics at runtime

    View Slide

  47. fun sumUp(items: Collection<*>) {a
    if (items is List) {d
    println(ints.sum())
    }b
    }c
    val strings: List = listOf("a", "b")
    sumUp(strings)

    View Slide

  48. fun sumUp(items: Collection<*>) {a
    if (items is List) {d
    println(ints.sum())
    }b
    }c
    val strings: List = listOf("a", "b")
    sumUp(strings)

    View Slide

  49. fun sumUp(items: Collection<*>) {a
    val ints = items as? List ?: return
    println("We got a list of ints")
    println(ints.sum())
    }c
    val strings: List = listOf("a", "b")
    sumUp(strings)

    View Slide

  50. fun sumUp(items: Collection<*>) {a
    val ints = items as? List ?: return
    println("We got a list of ints")
    println(ints.sum())
    }c
    val strings: List = listOf("a", "b")
    sumUp(strings)
    -----
    We got a list of ints
    Exception in thread "main" java.lang.ClassCastException:
    java.lang.String cannot be cast to java.lang.Number

    View Slide

  51. fun sumUp(items: Collection<*>) {a
    val ints = items as? List ?: return
    println("We got a list of ints")
    println(ints.sum())
    }c
    val strings: List = listOf("a", "b")
    sumUp(strings)

    View Slide

  52. fun sumUp(items: Collection) {a
    val ints = items as? List ?: return
    println("We got a list of ints")
    println(ints.sum())
    }c
    val strings: List = listOf("a", "b")
    sumUp(strings)

    View Slide

  53. View Slide

  54. fun Iterable<*>.filterIsInstance(): List {a
    val destination = mutableListOf()
    for (element in this) {c
    if (element is T) {d
    destination.add(element)
    }p
    }e
    return destination
    }f

    View Slide

  55. fun Iterable<*>.filterIsInstance(): List {a
    val destination = mutableListOf()
    for (element in this) {c
    if (element is T) {d
    destination.add(element)
    }p
    }e
    return destination
    }f
    listOf("a", 1, 0x0, 2L, 'u')
    .filterIsInstance()

    View Slide

  56. fun Iterable<*>.filterIsInstance(): List {a
    val destination = mutableListOf()
    for (element in this) {c
    if (element is T) {d
    destination.add(element)
    }p
    }e
    return destination
    }f
    listOf("a", 1, 0x0, 2L, 'u')
    .filterIsInstance()

    View Slide

  57. fun Iterable<*>.filterIsInstance(): List {a
    val destination = mutableListOf()
    for (element in this) {c
    if (element is T) {d
    destination.add(element)
    }p
    }e
    return destination
    }f
    listOf("a", 1, 0x0, 2L, 'u')
    .filterIsInstance()

    View Slide

  58. fun Iterable<*>.filterIsInstance(): List {a
    val destination = mutableListOf()
    for (element in this) {c
    if (element is T) {d
    destination.add(element)
    }p
    }e
    return destination
    }f

    View Slide

  59. View Slide

  60. fun Iterable<*>.filterIsInstance(): List {a
    val destination = mutableListOf()
    for (element in this) {c
    if (element is T) {d
    destination.add(element)
    }p
    }e
    return destination
    }f

    View Slide

  61. inline fun Iterable<*>.filterIsInstance(): List {a
    val destination = mutableListOf()
    for (element in this) {c
    if (element is T) {d
    destination.add(element)
    }p
    }e
    return destination
    }f

    View Slide

  62. inline fun Iterable<*>.filterIsInstance(): List
    val destination = mutableListOf()
    for (element in this) {c
    if (element is T) {d
    destination.add(element)
    }p
    }e
    return destination
    }f

    View Slide

  63. inline fun Iterable<*>.filterIsInstance(): List
    val destination = mutableListOf()
    for (element in this) {c
    if (element is T) {d
    destination.add(element)
    }p
    }e
    return destination
    }f

    View Slide

  64. inline fun Iterable<*>.filterIsInstance(): List
    val destination = mutableListOf()
    for (element in this) {c
    if (element is T) {d
    destination.add(element)
    }p
    }e
    return destination
    }f
    listOf("a", 1, 0x0, 2L, 'u')
    .filterIsInstance()

    View Slide

  65. View Slide

  66. val moshi = Moshi.Builder().build()
    moshi.adapter(String::class.java) // JsonAdapter

    View Slide

  67. val moshi = Moshi.Builder().build()
    moshi.adapter(String::class.java)

    View Slide

  68. val moshi = Moshi.Builder().build()
    moshi.adapter()

    View Slide

  69. inline fun Moshi.adapter(): JsonAdapter {a
    return this.adapter(T::class.java)
    }b
    val moshi = Moshi.Builder().build()
    moshi.adapter()

    View Slide

  70. View Slide

  71. If you really want to grow as a Klass,
    you've got to learn to delegate

    View Slide

  72. class canTbeextended
    open class canbeextended

    View Slide

  73. class CountingSet(
    val innerSet: MutableCollection = HashSet()
    ) : MutableCollection {abcdefgh
    }t

    View Slide

  74. class CountingSet(
    val innerSet: MutableCollection = HashSet()
    ) : MutableCollection {abcdefgh
    var objectsAdded = 0
    }t

    View Slide

  75. class CountingSet(
    val innerSet: MutableCollection = HashSet()
    ) : MutableCollection {abcdefgh
    var objectsAdded = 0
    override fun add(element: T): Boolean {w
    objectsAdded++
    return innerSet.add(element)
    }p
    override fun addAll(c: Collection): Boolean {o
    objectsAdded += c.size
    return innerSet.addAll(c)
    }k
    }t

    View Slide

  76. class CountingSet(
    val innerSet: MutableCollection = HashSet()
    ) : MutableCollection {abcdefgh
    var objectsAdded = 0
    override fun add(element: T): Boolean {w
    objectsAdded++
    return innerSet.add(element)
    }p
    override fun addAll(c: Collection): Boolean {o
    objectsAdded += c.size
    return innerSet.addAll(c)
    }k
    }t

    View Slide

  77. class CountingSet(
    val innerSet: MutableCollection = HashSet()
    ) : MutableCollection {abcdefgh
    var objectsAdded = 0
    override fun add(element: T): Boolean {w
    objectsAdded++
    return innerSet.add(element)
    }p
    override fun addAll(c: Collection): Boolean {o
    objectsAdded += c.size
    return innerSet.addAll(c)
    }k
    override val size: Int
    get() = innerSet.size
    override fun contains(element: T): Boolean {
    return innerSet.contains(element)
    }
    override fun containsAll(elements: Collection): Boolean {
    return innerSet.containsAll(elements)
    }
    override fun isEmpty(): Boolean {
    return innerSet.isEmpty()
    }
    override fun clear() {
    innerSet.clear()
    }
    override fun iterator(): MutableIterator {
    return innerSet.iterator()
    }
    override fun remove(element: T): Boolean {
    return innerSet.remove(element)
    }
    override fun removeAll(elements: Collection): Boolean {
    return innerSet.removeAll(elements)
    }
    override fun retainAll(elements: Collection): Boolean {
    return innerSet.retainAll(elements)
    }
    }t

    View Slide

  78. class CountingSet(
    val innerSet: MutableCollection = HashSet()
    ) : MutableCollection {abcdefgh
    var objectsAdded = 0
    override fun add(element: T): Boolean {w
    objectsAdded++
    return innerSet.add(element)
    }p
    override fun addAll(c: Collection): Boolean {o
    objectsAdded += c.size
    return innerSet.addAll(c)
    }k
    }t

    View Slide

  79. class CountingSet(
    val innerSet: MutableCollection = HashSet()
    ) : MutableCollection by innerSet {abcdefgh
    var objectsAdded = 0
    override fun add(element: T): Boolean {w
    objectsAdded++
    return innerSet.add(element)
    }p
    override fun addAll(c: Collection): Boolean {o
    objectsAdded += c.size
    return innerSet.addAll(c)
    }k
    }t

    View Slide

  80. class CountingSet(
    val innerSet: MutableCollection = HashSet()
    ) : MutableCollection by innerSet {abcdefgh
    var objectsAdded = 0
    override fun add(element: T): Boolean {w
    objectsAdded++
    return innerSet.add(element)
    }p
    override fun addAll(c: Collection): Boolean {o
    objectsAdded += c.size
    return innerSet.addAll(c)
    }k
    }t

    View Slide

  81. View Slide

  82. class Foo {
    val data: Int by lazy {
    computeStuff()
    }
    }
    • lazy
    • observable
    • vetoable
    • notNull

    View Slide

  83. The Secret of Success of to
    Triple Your Quotes

    View Slide

  84. """(.+)"(.+)"(.+)""".toRegex()
    new Regex("(.+)\"(.+)\"(.+)")
    "C:\\Users\\yole\\kotlin-book" """C:\Users\yole\kotlin-book"""
    """${'$'}99.9"""
    "\$99.9"
    "$99.9"
    Java Kotlin

    View Slide

  85. assertThat(toString(taco)).isEqualTo(""
    + "package com.squareup.tacos\n"
    + "\n"
    + "import kotlin.String\n"
    + "\n"
    + "class Taco {\n"
    + " final override fun toString(): String = \"taco\"\n"
    + "}\n"
    + "")c

    View Slide

  86. assertThat(toString(taco)).isEqualTo("""
    package com.squareup.tacos
    import kotlin.String
    class Taco {
    final override fun toString(): String = "taco"
    }z
    """)c

    View Slide

  87. assertThat(toString(taco)).isEqualTo("""
    package com.squareup.tacos
    import kotlin.String
    class Taco {
    final override fun toString(): String = "taco"
    }z
    """)c

    View Slide

  88. assertThat(toString(taco)).isEqualTo("""
    |package com.squareup.tacos
    |
    |import kotlin.String
    |
    |class Taco {
    | final override fun toString(): String = "taco"
    |}z
    |""")c

    View Slide

  89. assertThat(toString(taco)).isEqualTo("""
    |package com.squareup.tacos
    |
    |import kotlin.String
    |
    |class Taco {
    | final override fun toString(): String = "taco"
    |}
    |""".trimMargin())c

    View Slide

  90. View Slide

  91. And if you want these kind of dreams
    it's Deprecation

    View Slide

  92. class SomeList {a
    fun remove(index: Int) {b
    }c
    }f

    View Slide

  93. class SomeList {a
    fun remove(index: Int) {b
    }c
    fun removeAt(index: Int) {d
    }e
    }f

    View Slide

  94. class SomeList {a
    @Deprecated("Use removeAt(index) instead.")h
    fun remove(index: Int) {b
    }c
    fun removeAt(index: Int) {d
    }e
    }f

    View Slide

  95. class SomeList {a
    @Deprecated("Use removeAt(index) instead.",
    ReplaceWith("removeAt(index)"))h
    fun remove(index: Int) {b
    }c
    fun removeAt(index: Int) {d
    }e
    }f

    View Slide

  96. class SomeList {a
    @Deprecated("Use removeAt(index) instead.",
    ReplaceWith("removeAt(index)"))h
    fun remove(index: Int) {b
    }c
    fun removeAt(index: Int) {d
    }e
    }f

    View Slide

  97. Live Demo

    View Slide

  98. View Slide