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 full-size slide

  2. High Order Function's Extension

    View full-size slide

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

    View full-size slide

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

    View full-size 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 full-size 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 full-size 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 full-size 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 full-size 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 full-size 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 full-size 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 full-size 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 full-size 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 full-size slide

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

    View full-size slide

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

    View full-size slide

  16. When do we seal the casting?

    View full-size slide

  17. interface BinaryNumber
    object Zero : BinaryNumber
    object One : BinaryNumber

    View full-size slide

  18. 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 full-size 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
    }c
    }d

    View full-size 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
    else -> throw IllegalStateException()
    }c
    }d

    View full-size slide

  21. 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 full-size slide

  22. 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 full-size slide

  23. 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 full-size 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
    }c
    }d

    View full-size slide

  25. 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 full-size 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 full-size 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
    is Magic -> this.abracadabra()
    }c
    }d

    View full-size slide

  28. 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 full-size slide

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

    View full-size slide

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

    View full-size slide

  31. 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 full-size slide

  32. Error is Ever the Sequence of Haste

    View full-size slide

  33. people // List

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  42. Generics at runtime

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  45. 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 full-size slide

  46. 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 full-size slide

  47. 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 full-size slide

  48. 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 full-size slide

  49. 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 full-size slide

  50. 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 full-size slide

  51. 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 full-size slide

  52. 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 full-size slide

  53. 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 full-size 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 full-size slide

  55. 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 full-size slide

  56. 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 full-size slide

  57. 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 full-size slide

  58. 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 full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  64. class canTbeextended
    open class canbeextended

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  67. 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 full-size slide

  68. 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 full-size slide

  69. 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 full-size slide

  70. 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 full-size slide

  71. 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 full-size slide

  72. 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 full-size slide

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

    View full-size slide

  74. The Secret of Success of to
    Triple Your Quotes

    View full-size slide

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

    View full-size slide

  76. 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 full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  85. 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 full-size slide

  86. 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 full-size slide