Slide 1

Slide 1 text

Kotlin Features The Lesser-Known @antonarhipov

Slide 2

Slide 2 text

@antonarhipov

Slide 3

Slide 3 text

Why Kotlin?

Slide 4

Slide 4 text

Null-safety Coroutines Multiplatform Syntax Why Kotlin?

Slide 5

Slide 5 text

Null-safety Coroutines Multiplatform Syntax Why Kotlin?

Slide 6

Slide 6 text

Null-safety Coroutines Multiplatform Syntax Why Kotlin?

Slide 7

Slide 7 text

Null-safety Coroutines Multiplatform Syntax Why Kotlin?

Slide 8

Slide 8 text

Null-safety Coroutines Multiplatform Syntax Why Kotlin?

Slide 9

Slide 9 text

No content

Slide 10

Slide 10 text

Default values and named arguments

Slide 11

Slide 11 text

class Figure( val width: Int, val height: Int, val depth: Int, val color: Color, val description: String, )

Slide 12

Slide 12 text

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")

Slide 13

Slide 13 text

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")

Slide 14

Slide 14 text

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")

Slide 15

Slide 15 text

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")

Slide 16

Slide 16 text

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")

Slide 17

Slide 17 text

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)

Slide 18

Slide 18 text

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!

Slide 19

Slide 19 text

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)

Slide 20

Slide 20 text

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)

Slide 21

Slide 21 text

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)

Slide 22

Slide 22 text

Type-safe builders

Slide 23

Slide 23 text

No content

Slide 24

Slide 24 text

foo { bar { baz = "Hello!" qux = quux { corge = "Blah" } } }

Slide 25

Slide 25 text

foo { bar { baz = "Hello!" qux = quux { corge = "Blah" } } }

Slide 26

Slide 26 text

foo { bar { baz = "Hello!" qux = quux { corge = "Blah" } } }

Slide 27

Slide 27 text

foo { bar { baz = "Hello!" qux = quux { corge = "Blah" } } }

Slide 28

Slide 28 text

foo { bar(grault = 1) { baz = "Hello!" qux = quux { corge = "Blah" } } }

Slide 29

Slide 29 text

foo { bar(grault = 1) { baz = "Hello!" qux = quux { corge = Blah() } } }

Slide 30

Slide 30 text

foo { bar(grault = 1) { baz = "Hello!" qux = quux { corge = Blah() } } }

Slide 31

Slide 31 text

foo { bar(grault = 1) { baz = "Hello!" qux = quux { corge = Blah() } } } Named arguments

Slide 32

Slide 32 text

foo { bar(grault = 1) { baz = "Hello!" qux = quux { corge = Blah() } } } Higher-order functions

Slide 33

Slide 33 text

foo { bar(grault = 1) { baz = "Hello!" qux = quux { corge = Blah() } } } Trailing lambda

Slide 34

Slide 34 text

foo { bar(grault = 1) { baz = "Hello!" qux = quux { corge = Blah() } } } Extension function it: Foo fun Foo.bar(c: () -> Unit){ ... } it.

Slide 35

Slide 35 text

foo { bar(grault = 1) { baz = "Hello!" qux = quux { corge = Blah() } } } SAM-conversion fun quux(r: Runnable){ ... }

Slide 36

Slide 36 text

foo { bar(grault = 1) { baz = "Hello!" qux = quux { corge = Blah() } } } Lambda with receiver this: Foo fun foo(c: Foo.() -> Unit){ ... }

Slide 37

Slide 37 text

foo { bar(grault = 1) { baz = "Hello!" qux = quux { corge = Blah() } } } Lambda with receiver this: Foo fun foo(c: Foo.() -> Unit){ ... }

Slide 38

Slide 38 text

foo { bar(grault = 1) { baz = "Hello!" qux = quux { corge = Blah() } } } Lambda with receiver this: Foo fun foo(c: Foo.() -> Unit){ ... } DEMO TIME?

Slide 39

Slide 39 text

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) {}

Slide 40

Slide 40 text

+

Slide 41

Slide 41 text

@SpringBootApplication class DemoApplication fun main(args: Array) { runApplication(*args) }

Slide 42

Slide 42 text

@SpringBootApplication class DemoApplication fun main(args: Array) { runApplication(*args) } inline fun runApplication(vararg args: String): ConfigurableApplicationContext = SpringApplication.run(T :: class.java, *args)

Slide 43

Slide 43 text

@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)

Slide 44

Slide 44 text

@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)

Slide 45

Slide 45 text

@SpringBootApplication class DemoApplication fun main(args: Array) { runApplication(*args) { } } this: SpringApplication

Slide 46

Slide 46 text

@SpringBootApplication class DemoApplication fun main(args: Array) { runApplication(*args) { addInitializers(beans) } } this: SpringApplication

Slide 47

Slide 47 text

@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

Slide 48

Slide 48 text

@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

Slide 49

Slide 49 text

@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!")) } } }

Slide 50

Slide 50 text

T.() -> Unit

Slide 51

Slide 51 text

Builder inference

Slide 52

Slide 52 text

val list = buildList { }

Slide 53

Slide 53 text

val list = buildList { }

Slide 54

Slide 54 text

val list = buildList { }

Slide 55

Slide 55 text

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) }

Slide 56

Slide 56 text

val list = buildList { }

Slide 57

Slide 57 text

val list = buildList { val x = get(0) }

Slide 58

Slide 58 text

val list = buildList { val x = get(0) } Not enough type information

Slide 59

Slide 59 text

val list = buildList { val x: Int = get(0) } this: MutableList

Slide 60

Slide 60 text

val list = buildList { add("hello!") val x = get(0) } this: MutableList

Slide 61

Slide 61 text

val list = buildList { add("hello!") val x: Int = get(0) } this: MutableList

Slide 62

Slide 62 text

val list = buildList { add("hello!") val x: Int = get(0) } this: MutableList Type mismatch

Slide 63

Slide 63 text

val list = buildList { val x = get(0) doSomething(x) } this: MutableList fun doSomething(x: Int){…}

Slide 64

Slide 64 text

No content

Slide 65

Slide 65 text

Inline

Slide 66

Slide 66 text

fun main() { val ints = listOf(1,2,3,4) ints.forEveryOther { println(it) } }

Slide 67

Slide 67 text

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) } } }

Slide 68

Slide 68 text

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!

Slide 69

Slide 69 text

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) } } }

Slide 70

Slide 70 text

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() } }

Slide 71

Slide 71 text

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() } }

Slide 72

Slide 72 text

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() } }

Slide 73

Slide 73 text

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() } }

Slide 74

Slide 74 text

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

Slide 75

Slide 75 text

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

Slide 76

Slide 76 text

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() }

Slide 77

Slide 77 text

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() }

Slide 78

Slide 78 text

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() }

Slide 79

Slide 79 text

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() }

Slide 80

Slide 80 text

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() }

Slide 81

Slide 81 text

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

Slide 82

Slide 82 text

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) } } }

Slide 83

Slide 83 text

Noinline

Slide 84

Slide 84 text

inline fun Collection.forEveryOther(blockA: (Int) -> Unit, blockB: (Int) -> Unit, ) { ... doSomething(blockB) }

Slide 85

Slide 85 text

inline fun Collection.forEveryOther(blockA: (Int) -> Unit, blockB: (Int) -> Unit, ) { ... doSomething(blockB) } fun doSomething(block: (Int) -> Unit) { ... }

Slide 86

Slide 86 text

inline fun Collection.forEveryOther(blockA: (Int) -> Unit, blockB: (Int) -> Unit, ) { ... doSomething(blockB) } fun doSomething(block: (Int) -> Unit) { ... }

Slide 87

Slide 87 text

inline fun Collection.forEveryOther(blockA: (Int) -> Unit, noinline blockB: (Int) -> Unit, ) { ... doSomething(blockB) } fun doSomething(block: (Int) -> Unit) { ... }

Slide 88

Slide 88 text

inline fun Collection.forEveryOther(blockA: (Int) -> Unit, noinline blockB: (Int) -> Unit, ) { ... doSomething(blockB) } fun doSomething(block: (Int) -> Unit) { ... }

Slide 89

Slide 89 text

(Rei fi ed) Generics

Slide 90

Slide 90 text

@SpringBootApplication class DemoApplication fun main(args: Array) { runApplication(*args) } inline fun runApplication(vararg args: String): ConfigurableApplicationContext = SpringApplication.run(T :: class.java, *args)

Slide 91

Slide 91 text

@SpringBootApplication class DemoApplication fun main(args: Array) { runApplication(*args) } inline fun runApplication(vararg args: String): ConfigurableApplicationContext = SpringApplication.run(T :: class.java, *args)

Slide 92

Slide 92 text

fun printType() { println(T : : class.java) }

Slide 93

Slide 93 text

fun printType(c: Class) { println(c : : class.java) }

Slide 94

Slide 94 text

inline fun printType() { println(T : : class.java) }

Slide 95

Slide 95 text

inline fun printType() { println(T : : class.java) } fun printStringType(){ printType() }

Slide 96

Slide 96 text

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); }

Slide 97

Slide 97 text

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); }

Slide 98

Slide 98 text

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); }

Slide 99

Slide 99 text

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)

Slide 100

Slide 100 text

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

Slide 101

Slide 101 text

val list: List = listOf(1, "Hello", Color.RED) val strings: List = list.filterIsInstance() public inline fun Iterable < *> .filterIsInstance(): List { return filterIsInstanceTo(ArrayList()) }

Slide 102

Slide 102 text

Type-safe builders Functional literal (aka lambda) with receiver Builder inference Inline, crossinline, noinline (Rei fi ed) generics Some stdlib examples

Slide 103

Slide 103 text

Type-safe builders Functional literal (aka lambda) with receiver Builder inference Inline, crossinline, noinline (Rei fi ed) generics Some stdlib examples

Slide 104

Slide 104 text

Kotlin { YouTube = "youtube.com/kotlin" Slack = "slack.kotl.in" } me { name = "Anton Arhipov" twitter = "@antonarhipov" slides = speakerdeck.com/antonarhipov } this: Person this: Project