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

The Lesser-Known Kotlin Features

Anton Arhipov
September 13, 2022

The Lesser-Known Kotlin Features

The lesser-known Kotlin features

Kotlin is a modern programming language initially created as a "better Java." However, Kotlin provides not just a better syntax but a ton of new interesting features. In this session, you will learn about the subset of the lesser know features that might look obscure at first sight. How does the reified keyword in Kotlin work? What is the difference between inline and crossinline, and why is noinline required? Why do we need to indicate some types as "definitely non-nullable"? What's the deal with context receivers, and what's the lambda with the receiver? After this session, you will have an idea about the hidden Kotlin gems features and when to apply these advanced features.

Anton Arhipov

September 13, 2022
Tweet

More Decks by Anton Arhipov

Other Decks in Programming

Transcript

  1. Kotlin Features
    The Lesser-Known
    @antonarhipov

    View full-size slide

  2. @antonarhipov

    View full-size slide

  3. Null-safety


    Coroutines


    Multiplatform


    Syntax
    Why Kotlin?

    View full-size slide

  4. Null-safety


    Coroutines


    Multiplatform


    Syntax
    Why Kotlin?

    View full-size slide

  5. Null-safety


    Coroutines


    Multiplatform


    Syntax
    Why Kotlin?

    View full-size slide

  6. Null-safety


    Coroutines


    Multiplatform


    Syntax
    Why Kotlin?

    View full-size slide

  7. Null-safety


    Coroutines


    Multiplatform


    Syntax
    Why Kotlin?

    View full-size slide

  8. Default values


    and named arguments

    View full-size slide

  9. class Figure(


    val width: Int,


    val height: Int,


    val depth: Int,


    val color: Color,


    val description: String,


    )


    View full-size slide

  10. class Figure(


    val width: Int,


    val height: Int,


    val depth: Int,


    val color: Color,


    val description: String,


    )


    Figure(1, 2, 3, Color.RED, "Red brick")


    Figure(1, 1, 1, Color.GREEN, "Green cube")

    View full-size slide

  11. class Figure(


    val width: Int,


    val height: Int,


    val depth: Int,


    val color: Color,


    val description: String,


    )


    Figure(1, 2, 3, Color.RED, "Red brick")


    Figure(1, 1, 1, Color.GREEN, "Green cube")
    Figure(1, 1, 1, Color.BLUE, "Blue cube")

    View full-size slide

  12. class Figure(


    val width: Int,


    val height: Int,


    val depth: Int,


    val color: Color,


    val description: String,


    )


    Figure(1, 2, 3, Color.RED, "Red brick")


    Figure(1, 1, 1, Color.GREEN, "Green cube")
    Figure(1, 1, 1, Color.BLUE, "Blue cube")
    Figure(1, 1, 1, Color.BLACK, "Black cube")

    View full-size slide

  13. class Figure(


    val width: Int,


    val height: Int,


    val depth: Int,


    val color: Color,


    val description: String,


    )


    Figure(1, 2, 3, Color.RED, "Red brick")


    Figure(1, 1, 1, Color.GREEN, "Green cube")
    Figure(1, 1, 1, Color.BLUE, "Blue cube")
    Figure(1, 1, 1, Color.BLACK, "Black cube")

    View full-size slide

  14. class Figure(


    val width: Int = 1,


    val height: Int = 1,


    val depth: Int = 1,


    val color: Color = Color.BLACK,


    val description: String = "This is ${color} figure",


    )


    Figure(1, 2, 3, Color.RED, "Red brick")


    Figure(1, 1, 1, Color.GREEN, "Green cube")
    Figure(1, 1, 1, Color.BLUE, "Blue cube")
    Figure(1, 1, 1, Color.BLACK, "Black cube")

    View full-size slide

  15. class Figure(


    val width: Int = 1,


    val height: Int = 1,


    val depth: Int = 1,


    val color: Color = Color.BLACK,


    val description: String = "This is ${color} figure",


    )


    Figure(1, 2, 3, Color.RED, "Red brick")


    Figure(Color.GREEN)
    Figure(Color.BLUE)
    Figure(Color.BLACK)

    View full-size slide

  16. class Figure(


    val width: Int = 1,


    val height: Int = 1,


    val depth: Int = 1,


    val color: Color = Color.BLACK,


    val description: String = "This is ${color} figure",


    )


    Figure(1, 2, 3, Color.RED, "Red brick")


    Figure(Color.GREEN)
    Figure(Color.BLUE)
    Figure(Color.BLACK)
    Would not compile!

    View full-size slide

  17. class Figure(


    val width: Int = 1,


    val height: Int = 1,


    val depth: Int = 1,


    val color: Color = Color.BLACK,


    val description: String = "This is ${color} figure",


    )


    Figure(1, 2, 3, Color.RED, "Red brick")


    Figure(color = Color.GREEN)
    Figure(color = Color.BLUE)
    Figure(color = Color.BLACK)

    View full-size slide

  18. class Figure(


    val width: Int = 1,


    val height: Int = 1,


    val depth: Int = 1,


    val color: Color = Color.BLACK,


    val description: String = "This is ${color} figure",


    )


    Figure(width = 1, height = 2, depth = 3, Color.RED, "Red brick")


    Figure(color = Color.GREEN)
    Figure(color = Color.BLUE)
    Figure(color = Color.BLACK)

    View full-size slide

  19. class Figure(


    val width: Int = 1,


    val height: Int = 1,


    val depth: Int = 1,


    val color: Color = Color.BLACK,


    val description: String = "This is ${color} figure",


    )


    Figure(width = 1, height = 2, depth = 3, Color.RED, "Red brick")


    Figure(color = Color.GREEN)
    Figure(color = Color.BLUE)
    Figure(color = Color.BLACK)

    View full-size slide

  20. Type-safe builders

    View full-size slide

  21. foo {


    bar {


    baz = "Hello!"


    qux = quux {


    corge = "Blah"


    }


    }


    }

    View full-size slide

  22. foo {


    bar {


    baz = "Hello!"


    qux = quux {


    corge = "Blah"


    }


    }


    }

    View full-size slide

  23. foo {


    bar {


    baz = "Hello!"


    qux = quux {


    corge = "Blah"


    }


    }


    }

    View full-size slide

  24. foo {


    bar {


    baz = "Hello!"


    qux = quux {


    corge = "Blah"


    }


    }


    }

    View full-size slide

  25. foo {


    bar(grault = 1) {


    baz = "Hello!"


    qux = quux {


    corge = "Blah"


    }


    }


    }

    View full-size slide

  26. foo {


    bar(grault = 1) {


    baz = "Hello!"


    qux = quux {


    corge = Blah()


    }


    }


    }

    View full-size slide

  27. foo {


    bar(grault = 1) {


    baz = "Hello!"


    qux = quux {


    corge = Blah()


    }


    }


    }

    View full-size slide

  28. foo {


    bar(grault = 1) {


    baz = "Hello!"


    qux = quux {


    corge = Blah()


    }


    }


    }
    Named arguments

    View full-size slide

  29. foo {


    bar(grault = 1) {


    baz = "Hello!"


    qux = quux {


    corge = Blah()


    }


    }


    }
    Higher-order functions

    View full-size slide

  30. foo {


    bar(grault = 1) {


    baz = "Hello!"


    qux = quux {


    corge = Blah()


    }


    }


    }
    Trailing lambda

    View full-size slide

  31. foo {


    bar(grault = 1) {


    baz = "Hello!"


    qux = quux {


    corge = Blah()


    }


    }


    }
    Extension function
    it: Foo
    fun Foo.bar(c: ()
    ->
    Unit){
    ...
    }


    it.

    View full-size slide

  32. foo {


    bar(grault = 1) {


    baz = "Hello!"


    qux = quux {


    corge = Blah()


    }


    }


    }
    SAM-conversion
    fun quux(r: Runnable){
    ...
    }


    View full-size slide

  33. foo {


    bar(grault = 1) {


    baz = "Hello!"


    qux = quux {


    corge = Blah()


    }


    }


    }
    Lambda with receiver
    this: Foo
    fun foo(c: Foo.()
    ->
    Unit){
    ...
    }


    View full-size slide

  34. foo {


    bar(grault = 1) {


    baz = "Hello!"


    qux = quux {


    corge = Blah()


    }


    }


    }
    Lambda with receiver
    this: Foo
    fun foo(c: Foo.()
    ->
    Unit){
    ...
    }


    View full-size slide

  35. foo {


    bar(grault = 1) {


    baz = "Hello!"


    qux = quux {


    corge = Blah()


    }


    }


    }
    Lambda with receiver
    this: Foo
    fun foo(c: Foo.()
    ->
    Unit){
    ...
    }


    DEMO TIME?

    View full-size slide

  36. Kotlin DSL in TeamCity
    project {


    vcsRoot(ApplicationVcs)


    buildType {


    id("Application")


    name = "Application"


    vcs { root(ApplicationVcs) }


    artifactRules = "target/*jar"


    steps {


    maven { goals = "clean package" }


    }


    triggers { vcs {} }


    dependencies {


    snapshot(Library) {}




    View full-size slide

  37. @SpringBootApplication


    class DemoApplication


    fun main(args: Array) {


    runApplication(*args)


    }


    View full-size slide

  38. @SpringBootApplication


    class DemoApplication


    fun main(args: Array) {


    runApplication(*args)


    }


    inline fun runApplication(vararg args: String): ConfigurableApplicationContext =


    SpringApplication.run(T
    ::
    class.java, *args)


    View full-size slide

  39. @SpringBootApplication


    class DemoApplication


    fun main(args: Array) {


    runApplication(*args)


    }


    inline fun runApplication(vararg args: String): ConfigurableApplicationContext =


    SpringApplication.run(T
    ::
    class.java, *args)


    inline fun runApplication(vararg args: String, init: SpringApplication.()
    ->
    Unit):


    ConfigurableApplicationContext =


    SpringApplication.run(T
    ::
    class.java).apply(init).run(*args)


    View full-size slide

  40. @SpringBootApplication


    class DemoApplication


    fun main(args: Array) {


    runApplication(*args)


    }


    inline fun runApplication(vararg args: String): ConfigurableApplicationContext =


    SpringApplication.run(T
    ::
    class.java, *args)


    inline fun runApplication(vararg args: String, init: SpringApplication.()
    ->
    Unit):


    ConfigurableApplicationContext =


    SpringApplication.run(T
    ::
    class.java).apply(init).run(*args)


    View full-size slide

  41. @SpringBootApplication


    class DemoApplication


    fun main(args: Array) {


    runApplication(*args) {




    }


    }


    this: SpringApplication

    View full-size slide

  42. @SpringBootApplication


    class DemoApplication


    fun main(args: Array) {


    runApplication(*args) {


    addInitializers(beans)


    }


    }


    this: SpringApplication

    View full-size slide

  43. @SpringBootApplication


    class DemoApplication


    fun main(args: Array) {


    runApplication(*args) {


    addInitializers(beans)


    }


    }


    val beans = beans {


    bean {


    CommandLineRunner {


    println("start data initialization
    ...
    ")


    val repository = ref()


    repository.save(Message(text = "this is the first message!"))


    repository.save(Message(text = "this is the second message!"))


    }


    }


    }


    this: SpringApplication

    View full-size slide

  44. @SpringBootApplication


    class DemoApplication


    fun main(args: Array) {


    runApplication(*args) {


    addInitializers(beans)


    }


    }


    val beans = beans {


    bean {


    CommandLineRunner {


    println("start data initialization
    ...
    ")


    val repository = ref()


    repository.save(Message(text = "this is the first message!"))


    repository.save(Message(text = "this is the second message!"))


    }


    }


    }


    this: SpringApplication
    this: BeanDefinitionDsl
    this: BeanDefinitionDsl.BeanSupplierContext
    it: Array

    View full-size slide

  45. @SpringBootApplication


    class DemoApplication


    fun main(args: Array) {


    runApplication(*args) {


    addInitializers(beans)


    }


    }


    val beans = beans {


    bean {


    CommandLineRunner {


    println("start data initialization
    ...
    ")


    val repository = ref()


    repository.save(Message(text = "this is the first message!"))


    repository.save(Message(text = "this is the second message!"))


    }


    }


    }


    View full-size slide

  46. Builder inference

    View full-size slide

  47. val list = buildList {


    }


    View full-size slide

  48. val list = buildList {


    }


    View full-size slide

  49. val list = buildList {


    }


    View full-size slide

  50. val list = buildList {


    }


    @SinceKotlin("1.6")


    @WasExperimental(ExperimentalStdlibApi
    ::
    class)


    @kotlin.internal.InlineOnly


    @Suppress("DEPRECATION")


    public inline fun buildList(@BuilderInference builderAction: MutableList.()
    - >
    Unit): List


    contract { callsInPlace(builderAction, InvocationKind.EXACTLY_ONCE) }


    return buildListInternal(builderAction)


    }


    View full-size slide

  51. val list = buildList {


    }


    View full-size slide

  52. val list = buildList {


    val x = get(0)


    }


    View full-size slide

  53. val list = buildList {


    val x = get(0)


    }


    Not enough type information

    View full-size slide

  54. val list = buildList {


    val x: Int = get(0)


    }


    this: MutableList

    View full-size slide

  55. val list = buildList {


    add("hello!")


    val x = get(0)


    }
    this: MutableList

    View full-size slide

  56. val list = buildList {


    add("hello!")


    val x: Int = get(0)


    }
    this: MutableList

    View full-size slide

  57. val list = buildList {


    add("hello!")


    val x: Int = get(0)


    }
    this: MutableList
    Type mismatch

    View full-size slide

  58. val list = buildList {


    val x = get(0)


    doSomething(x)


    }
    this: MutableList
    fun doSomething(x: Int){…}

    View full-size slide

  59. fun main() {


    val ints = listOf(1,2,3,4)


    ints.forEveryOther { println(it) }


    }


    View full-size slide

  60. fun main() {


    val ints = listOf(1,2,3,4)


    ints.forEveryOther { println(it) }


    }


    inline fun Collection.forEveryOther(block: (Int)
    ->
    Unit) {


    for ((i, element) in withIndex()) {


    if (i % 2
    ==
    0) {


    block(element)


    }


    }


    }


    View full-size slide

  61. fun main() {


    val ints = listOf(1,2,3,4)


    ints.forEveryOther { println(it) }


    }


    inline fun Collection.forEveryOther(block: (Int)
    ->
    Unit) {


    for ((i, element) in withIndex()) {


    if (i % 2
    ==
    0) {


    block(element)


    }


    }


    }


    Inlines everything!

    View full-size slide

  62. fun main() {


    val ints = listOf(1,2,3,4)


    for ((i, element) in withIndex()) {


    if (i % 2
    ==
    0) {


    println(element)


    }


    }


    }


    inline fun Collection.forEveryOther(block: (Int)
    ->
    Unit) {


    for ((i, element) in withIndex()) {


    if (i % 2
    ==
    0) {


    block(element)


    }


    }


    }


    View full-size slide

  63. fun main() {


    val ints = listOf(1,2,3,4)


    ints.forEveryOther { println(it) }


    }


    inline fun Collection.forEveryOther(block: (Int)
    ->
    Unit) {


    for ((i, element) in withIndex()) {


    val task = Runnable {


    if (i % 2
    ==
    0) {


    block(element)


    }


    }


    task.run()


    }


    }


    View full-size slide

  64. fun main() {


    val ints = listOf(1,2,3,4)


    ints.forEveryOther { println(it) }


    }


    inline fun Collection.forEveryOther(block: (Int)
    ->
    Unit) {


    for ((i, element) in withIndex()) {


    val task = Runnable {


    if (i % 2
    ==
    0) {


    block(element)


    }


    }


    task.run()


    }


    }


    View full-size slide

  65. fun main() {


    val ints = listOf(1,2,3,4)


    ints.forEveryOther { println(it) }


    }


    inline fun Collection.forEveryOther(block: (Int)
    ->
    Unit) {


    for ((i, element) in withIndex()) {


    val task = Runnable {


    if (i % 2
    ==
    0) {


    block(element)


    }


    }


    task.run()


    }


    }


    View full-size slide

  66. fun main() {


    val ints = listOf(1,2,3,4)


    ints.forEveryOther { println(it) }


    }


    inline fun Collection.forEveryOther(block: (Int)
    ->
    Unit) {


    for ((i, element) in withIndex()) {


    val task = Runnable {


    if (i % 2
    ==
    0) {


    block(element)


    }


    }


    task.run()


    }


    }


    View full-size slide

  67. fun main() {


    val ints = listOf(1,2,3,4)


    ints.forEveryOther {


    if(it
    ==
    3) return


    println(it)


    }


    }


    inline fun Collection.forEveryOther(block: (Int)
    ->
    Unit) {


    for ((i, element) in withIndex()) {


    val task = Runnable {


    if (i % 2
    ==
    0) {


    block(element)


    }


    }


    task.run()


    }




    Non-local return
    Returns from main

    View full-size slide

  68. fun main() {


    val ints = listOf(1,2,3,4)


    ints.forEveryOther l@{


    if(it
    ==
    3) return@l


    println(it)


    }


    }


    inline fun Collection.forEveryOther(block: (Int)
    ->
    Unit) {


    for ((i, element) in withIndex()) {


    val task = Runnable {


    if (i % 2
    ==
    0) {


    block(element)


    }


    }


    task.run()


    }




    Local return
    Returns from lambda

    View full-size slide

  69. fun main() {


    val ints = listOf(1,2,3,4)


    ints.forEveryOther l@{


    if(it
    ==
    3) return@l


    println(it)


    }


    }


    inline fun Collection.forEveryOther(block: (Int)
    ->
    Unit) {


    for ((i, element) in withIndex()) {


    val task = Runnable {


    if (i % 2
    ==
    0) {


    block(element)


    }


    }


    task.run()


    }




    View full-size slide

  70. fun main() {


    val ints = listOf(1,2,3,4)


    ints.forEveryOther l@{


    if(it
    ==
    3) return@l


    println(it)


    }


    }


    inline fun Collection.forEveryOther(crossinline block: (Int)
    ->
    Unit) {


    for ((i, element) in withIndex()) {


    val task = Runnable {


    if (i % 2
    ==
    0) {


    block(element)


    }


    }


    task.run()


    }




    View full-size slide

  71. fun main() {


    val ints = listOf(1,2,3,4)


    ints.forEveryOther {


    if(it
    ==
    3) return


    println(it)


    }


    }


    inline fun Collection.forEveryOther(crossinline block: (Int)
    ->
    Unit) {


    for ((i, element) in withIndex()) {


    val task = Runnable {


    if (i % 2
    ==
    0) {


    block(element)


    }


    }


    task.run()


    }




    View full-size slide

  72. fun main() {


    val ints = listOf(1,2,3,4)


    ints.forEveryOther {


    if(it
    ==
    3) return


    println(it)


    }


    }


    inline fun Collection.forEveryOther(crossinline block: (Int)
    ->
    Unit) {


    for ((i, element) in withIndex()) {


    val task = Runnable {


    if (i % 2
    ==
    0) {


    block(element)


    }


    }


    task.run()


    }




    View full-size slide

  73. fun main() {


    val ints = listOf(1,2,3,4)


    ints.forEveryOther l@{


    if(it
    ==
    3) return@l


    println(it)


    }


    }


    inline fun Collection.forEveryOther(crossinline block: (Int)
    ->
    Unit) {


    for ((i, element) in withIndex()) {


    val task = Runnable {


    if (i % 2
    ==
    0) {


    block(element)


    }


    }


    task.run()


    }




    View full-size slide

  74. fun main() {


    val ints = listOf(1,2,3,4)


    ints.forEveryOther l@{


    if(it
    ==
    3) return@l


    println(it)


    }


    }


    inline fun Collection.forEveryOther(crossinline block: (Int)
    ->
    Unit) {


    for ((i, element) in withIndex()) {


    val task = Runnable {


    if (i % 2
    ==
    0) {


    block(element)


    }


    }


    task.run()


    }




    Inlines the loop
    Lambda is compiled


    to a separate class

    View full-size slide

  75. fun main() {


    val ints = listOf(1,2,3,4)


    for ((i, element) in withIndex()) {


    val task: Runnable = (Runnable)Kt$inlined$forEveryOther(i, element)


    task.run()


    }


    }
    class Kt$inlined$forEveryOther implements Runnable {


    . ..

    public final run(){


    if (i % 2
    ==
    0) {


    if(element
    !
    =
    3)


    System.out.println(element)


    }


    }


    }

    View full-size slide

  76. inline fun Collection.forEveryOther(blockA: (Int)
    ->
    Unit,


    blockB: (Int)
    ->
    Unit, ) {



    ...

    doSomething(blockB)


    }


    View full-size slide

  77. inline fun Collection.forEveryOther(blockA: (Int)
    ->
    Unit,


    blockB: (Int)
    ->
    Unit, ) {



    ...

    doSomething(blockB)


    }


    fun doSomething(block: (Int)
    ->
    Unit) {


    ...

    }

    View full-size slide

  78. inline fun Collection.forEveryOther(blockA: (Int)
    ->
    Unit,


    blockB: (Int)
    ->
    Unit, ) {



    ...

    doSomething(blockB)


    }


    fun doSomething(block: (Int)
    ->
    Unit) {


    ...

    }

    View full-size slide

  79. inline fun Collection.forEveryOther(blockA: (Int)
    ->
    Unit,


    noinline blockB: (Int)
    ->
    Unit, ) {



    ...

    doSomething(blockB)


    }


    fun doSomething(block: (Int)
    ->
    Unit) {


    ...

    }

    View full-size slide

  80. inline fun Collection.forEveryOther(blockA: (Int)
    ->
    Unit,


    noinline blockB: (Int)
    ->
    Unit, ) {



    ...

    doSomething(blockB)


    }


    fun doSomething(block: (Int)
    ->
    Unit) {


    ...

    }

    View full-size slide

  81. (Rei
    fi
    ed) Generics

    View full-size slide

  82. @SpringBootApplication


    class DemoApplication


    fun main(args: Array) {


    runApplication(*args)


    }


    inline fun runApplication(vararg args: String):


    ConfigurableApplicationContext =


    SpringApplication.run(T
    ::
    class.java, *args)


    View full-size slide

  83. @SpringBootApplication


    class DemoApplication


    fun main(args: Array) {


    runApplication(*args)


    }


    inline fun runApplication(vararg args: String):


    ConfigurableApplicationContext =


    SpringApplication.run(T
    ::
    class.java, *args)


    View full-size slide

  84. fun printType() {


    println(T
    : :
    class.java)


    }

    View full-size slide

  85. fun printType(c: Class) {


    println(c
    : :
    class.java)


    }

    View full-size slide

  86. inline fun printType() {


    println(T
    : :
    class.java)


    }

    View full-size slide

  87. inline fun printType() {


    println(T
    : :
    class.java)


    }
    fun printStringType(){


    printType()


    }


    View full-size slide

  88. inline fun printType() {


    println(T
    ::
    class.java)


    }
    fun printStringType(){


    printType()


    }


    public static final void printType() {


    int $i$f$printType = 0;


    Intrinsics.reifiedOperationMarker(4, "T");


    Class var1 = Object.class;


    System.out.println(var1);


    }


    public static final void printStringType() {


    int $i$f$printType = false;


    Class var1 = String.class;


    System.out.println(var1);


    }


    View full-size slide

  89. inline fun printType() {


    println(T
    ::
    class.java)


    }
    fun printStringType(){


    printType()


    }


    public static final void printType() {


    int $i$f$printType = 0;


    Intrinsics.reifiedOperationMarker(4, "T");


    Class var1 = Object.class;


    System.out.println(var1);


    }


    public static final void printStringType() {


    int $i$f$printType = false;


    Class var1 = String.class;


    System.out.println(var1);


    }


    View full-size slide

  90. inline fun printType() {


    println(T
    ::
    class.java)


    }
    fun printStringType(){


    printType()


    }


    public static final void printType() {


    int $i$f$printType = 0;


    Intrinsics.reifiedOperationMarker(4, "T");


    Class var1 = Object.class;


    System.out.println(var1);


    }


    public static final void printStringType() {


    int $i$f$printType = false;


    Class var1 = String.class;


    System.out.println(var1);


    }


    View full-size slide

  91. inline fun calculate(value: Float): T {


    return when (T
    ::
    class) {


    Int
    ::
    class
    ->
    value.toInt() as T


    Float
    ::
    class
    ->
    value as T


    else
    ->
    throw IllegalArgumentException("$value is neither Float or Int")


    }


    }


    val intValue: Int = calculate(123f)


    val floatValue: Float = calculate(123f)

    View full-size slide

  92. val list: List = listOf(1, "Hello", Color.RED)


    val strings: List = list.filterIsInstance()


    View full-size slide

  93. val list: List = listOf(1, "Hello", Color.RED)


    val strings: List = list.filterIsInstance()


    public inline fun Iterable
    < *>
    .filterIsInstance(): List {


    return filterIsInstanceTo(ArrayList())


    }


    View full-size slide

  94. Type-safe builders


    Functional literal (aka lambda) with receiver


    Builder inference


    Inline, crossinline, noinline


    (Rei
    fi
    ed) generics


    Some stdlib examples

    View full-size slide

  95. Type-safe builders


    Functional literal (aka lambda) with receiver


    Builder inference


    Inline, crossinline, noinline


    (Rei
    fi
    ed) generics


    Some stdlib examples

    View full-size slide

  96. Kotlin {


    YouTube = "youtube.com/kotlin"


    Slack = "slack.kotl.in"


    }
    me {


    name = "Anton Arhipov"


    twitter = "@antonarhipov"


    slides = speakerdeck.com/antonarhipov


    }
    this: Person
    this: Project

    View full-size slide