Slide 1

Slide 1 text

Kotlin Anton Arhipov @antonarhipov Developer Advocate, JetBrains Introduction to Kotlin International Winter School on Software Engineering @antonarhipov

Slide 2

Slide 2 text

Kotlin’s (very simplified) history in one slide 2011 - announced as an alternative JVM language

Slide 3

Slide 3 text

Kotlin’s (very simplified) history in one slide 2011 - announced as an alternative JVM language 2014 - Kotlin 1.0 2013 - Kotlin/JS

Slide 4

Slide 4 text

Kotlin’s (very simplified) history in one slide 2011 - announced as an alternative JVM language 2016 - Kotlin 1.0 2017 - Kotlin/Native preview 2016 - Experimental coroutines (Kotlin 1.1) 2013 - Kotlin/JS

Slide 5

Slide 5 text

Kotlin’s (very simplified) history in one slide 2011 - announced as an alternative JVM language 2016 - Kotlin 1.0 2017 - Kotlin/Native preview 2016 - Experimental coroutines (Kotlin 1.1) 2018 - Multiplatform projects - experimental (Kotlin 1.2) 2019 - Main programming language for Android 2013 - Kotlin/JS 2018 - Coroutines release (Kotlin 1.3)

Slide 6

Slide 6 text

Kotlin’s (very simplified) history in one slide 2011 - announced as an alternative JVM language 2016 - Kotlin 1.0 Current version: 1.6.20 2017 - Kotlin/Native preview 2021 - started with Kotlin/WASM 2016 - Experimental coroutines (Kotlin 1.1) 2018 - Multiplatform projects - experimental (Kotlin 1.2) 2019 - Main programming language for Android 2013 - Kotlin/JS 2018 - Coroutines release (Kotlin 1.3)

Slide 7

Slide 7 text

Kotlin’s (very simplified) description Modern Functional Multiplatform Statically-typed Asynchronous (with coroutines) General purpose Object-oriented

Slide 8

Slide 8 text

No content

Slide 9

Slide 9 text

Books https://kotlinlang.org/docs/books.html

Slide 10

Slide 10 text

No content

Slide 11

Slide 11 text

No content

Slide 12

Slide 12 text

Kotlin Basics

Slide 13

Slide 13 text

// entry point fun main(args: Array) { println("Hello World!") } Program entry point

Slide 14

Slide 14 text

// entry point fun main(args: Array) { println("Hello World!") } Program entry point // alternatively fun main() { println("Hello World!") }

Slide 15

Slide 15 text

Variables fun someFunction() { val a: Int = 1 // immediate assignment val b = 2 // `Int` type is inferred val c: Int // Type required when no initializer is provided c = 3 // deferred assignment // .. . }

Slide 16

Slide 16 text

Variables val PI = 3.14 var x = 0 fun incrementX() { x += 1 }

Slide 17

Slide 17 text

Variables val PI: Double = 3.14 var x: Int = 0 val s: String = "Hello" Double PI = 3.14; Integer x = 0; String s = "Hello"; Explicit types Explicit types

Slide 18

Slide 18 text

Variables val PI: Double = 3.14 var x: Int = 0 val s: String = "Hello" val PI = 3.14 var x = 0 val s = "Hello" Double PI = 3.14; Integer x = 0; String s = "Hello"; Explicit types Type inference final var PI = 3.14; var x = 0; final var s = "Hello"; Type inference (local variables) Explicit types

Slide 19

Slide 19 text

Functions fun sum(a: Int, b: Int): Int { return a + b }

Slide 20

Slide 20 text

Functions fun sum(a: Int, b: Int): Int { return a + b }

Slide 21

Slide 21 text

Functions fun sum(a: Int, b: Int): Int { return a + b } // expression body fun sum(a: Int, b: Int): Int = a + b

Slide 22

Slide 22 text

Functions fun sum(a: Int, b: Int): Int { return a + b } // expression body fun sum(a: Int, b: Int): Int = a + b // type inference fun sum(a: Int, b: Int) = a + b

Slide 23

Slide 23 text

Functions // return no value fun printSum(a: Int, b: Int): Unit { println("sum of $a and $b is ${a + b}") }

Slide 24

Slide 24 text

Functions // return no value fun printSum(a: Int, b: Int): Unit { println("sum of $a and $b is ${a + b}") } // Unit can be omitted fun printSum(a: Int, b: Int) { println("sum of $a and $b is ${a + b}") }

Slide 25

Slide 25 text

fun main(args: Array) { "Hello World!".say() } Extension functions

Slide 26

Slide 26 text

fun main(args: Array) { "Hello World!".say() } private fun String.say() { println(this) } Extension functions

Slide 27

Slide 27 text

Functions as parameters fun main(args: Array) { process { s -> println("Hello, $s!") } } fun process(operation: (String) -> Unit) { operation("World") }

Slide 28

Slide 28 text

Lambda expressions val sum: (Int, Int) -> Int = { x: Int, y: Int - > x + y }

Slide 29

Slide 29 text

Lambda expressions val sum: (Int, Int) -> Int = { x: Int, y: Int - > x + y } val sum = { x: Int, y: Int -> x + y }

Slide 30

Slide 30 text

Lambda expressions val sum: (Int, Int) -> Int = { x: Int, y: Int - > x + y } val sum = { x: Int, y: Int -> x + y } typealias IntAdder = (Int, Int) -> Int val sum: IntAdder = { x: Int, y: Int -> x + y }

Slide 31

Slide 31 text

Default values fun find(name: String){ find(name, true) } fun find(name: String, recursive: Boolean){ } Function overloading

Slide 32

Slide 32 text

Default values fun find(name: String){ find(name, true) } fun find(name: String, recursive: Boolean = true){ } Default value

Slide 33

Slide 33 text

Default values fun find(name: String){ find(name, true) } fun find(name: String, recursive: Boolean = true){ } fun main(args: Array) { find("myfile.txt") }

Slide 34

Slide 34 text

class Figure( val width: Int = 1, val height: Int = 1, val depth: Int = 1, color: Color = Color.BLACK, description: String = "This is a 3d figure", ) Default values + named arguments

Slide 35

Slide 35 text

class Figure( val width: Int = 1, val height: Int = 1, val depth: Int = 1, color: Color = Color.BLACK, description: String = "This is a 3d figure", ) Default values + named arguments Figure(Color.RED, "Red figure")

Slide 36

Slide 36 text

class Figure( val width: Int = 1, val height: Int = 1, val depth: Int = 1, color: Color = Color.BLACK, description: String = "This is a 3d figure", ) Default values + named arguments Figure(color = Color.RED, description = "Red figure")

Slide 37

Slide 37 text

Default values + named arguments Default argument values diminish the need for overloading in most cases. Named parameters is a necessary tool for working with default argument values

Slide 38

Slide 38 text

Operator overloading To implement an operator, provide a member function or an extension function with a specific name for the corresponding type.

Slide 39

Slide 39 text

Operator overloading To implement an operator, provide a member function or an extension function with a specific name for the corresponding type. data class Point(val x: Int, val y: Int) operator fun Point.unaryMinus() = Point(-x, -y) val point = Point(10, 20) fun main() { println(-point) // prints "Point(x=-10, y=-20)" }

Slide 40

Slide 40 text

Expressions fun adjustSpeed(weather: Weather): Drive { val result: Drive if (weather is Rainy) { result = Safe } else { result = Calm } return result }

Slide 41

Slide 41 text

Expressions fun adjustSpeed(weather: Weather): Drive { val result: Drive if (weather is Rainy) { result = Safe } else { result = Calm } return result } fun adjustSpeed(weather: Weather) = if (weather is Rainy) Safe else Calm Note to myself: show in the IDE

Slide 42

Slide 42 text

Expressions fun adjustSpeed(weather: Weather) = if (weather is Rainy) Safe else Calm Is it concise? Sure!

Slide 43

Slide 43 text

Expressions fun adjustSpeed(weather: Weather) = if (weather is Rainy) Safe else Calm Is it readable? It depends!

Slide 44

Slide 44 text

Expressions fun adjustSpeed(weather: Weather) = if (weather is Rainy) Safe else Calm What does the function return?

Slide 45

Slide 45 text

Expressions fun adjustSpeed(weather: Weather) : Drive = ... private fun adjustSpeed(weather: Weather) = For public API, keep the return type in the signature For private API it is generally OK to use type inference

Slide 46

Slide 46 text

Expressions The expressions if, try, and when can return values as a result Note to myself: show in the IDE

Slide 47

Slide 47 text

fun adjustSpeed(weather: Weather): Drive = when (weather) { is Rainy -> Safe else - > Calm } ‘when’ expression is exhaustive for sealed classes, enums and booleans

Slide 48

Slide 48 text

fun adjustSpeed(weather: Weather): Drive = when (weather) { is Rainy -> Safe // else -> Calm } Compilation error: We should either specify all options or use the ‘else’ branch sealed class Weather object Rainy : Weather() object Sunny : Weather()

Slide 49

Slide 49 text

Ranges val x = 10 val y = 9 if (x in 1 .. y+1) { println("fits in range") }

Slide 50

Slide 50 text

Ranges: iteration for (x in 1 . . 5) { print(x) }

Slide 51

Slide 51 text

Ranges: iteration for (x in 1 . . 5) { print(x) } for (x in 1 . . 10 step 2) { print(x) } for (x in 9 downTo 0 step 3) { print(x) }

Slide 52

Slide 52 text

fun isLatinUppercase(c: Char) = c >= 'A' & & c < = 'Z' Use range checks instead of comparison pairs

Slide 53

Slide 53 text

fun isLatinUppercase(c: Char) = c >= 'A' & & c < = 'Z' fun isLatinUppercase(c: Char) = c in 'A' .. 'Z' Use range checks instead of comparison pairs

Slide 54

Slide 54 text

class Version(val major: Int, val minor: Int): Comparable { override fun compareTo(other: Version): Int { if (this.major ! = other.major) { return this.major - other.major } return this.minor - other.minor } } fun main() { val versionRange = Version(1, 11) . . Version(1, 30) println(Version(0, 9) in versionRange) println(Version(1, 20) in versionRange) } Comparable range

Slide 55

Slide 55 text

class Version(val major: Int, val minor: Int): Comparable { override fun compareTo(other: Version): Int { if (this.major ! = other.major) { return this.major - other.major } return this.minor - other.minor } } fun main() { val versionRange = Version(1, 11) . . Version(1, 30) println(Version(0, 9) in versionRange) println(Version(1, 20) in versionRange) } Comparable range public operator fun > T.rangeTo(that: T): ClosedRange = ComparableRange(this, that)

Slide 56

Slide 56 text

class Version(val major: Int, val minor: Int): Comparable { override fun compareTo(other: Version): Int { if (this.major ! = other.major) { return this.major - other.major } return this.minor - other.minor } } fun main() { val versionRange = Version(1, 11) . . Version(1, 30) println(Version(0, 9) in versionRange) println(Version(1, 20) in versionRange) } Comparable range public operator fun > T.rangeTo(that: T): ClosedRange = ComparableRange(this, that)

Slide 57

Slide 57 text

Ranges in loops fun main(args: Array) { for (i in 0 .. args.size - 1) { println("$i: ${args[i]}") } }

Slide 58

Slide 58 text

Ranges in loops fun main(args: Array) { for (i in 0 .. args.size - 1) { println("$i: ${args[i]}") } }

Slide 59

Slide 59 text

Ranges in loops fun main(args: Array) { for (i in 0 .. args.size - 1) { println("$i: ${args[i]}") } } for (i in 0 until args.size) { println("$i: ${args[i]}") }

Slide 60

Slide 60 text

Ranges in loops fun main(args: Array) { for (i in 0 .. args.size - 1) { println("$i: ${args[i]}") } } for (i in 0 until args.size) { println("$i: ${args[i]}") } for (i in args.indices) { println("$i: ${args[i]}") }

Slide 61

Slide 61 text

Ranges in loops fun main(args: Array) { for (i in 0 .. args.size - 1) { println("$i: ${args[i]}") } } for (i in 0 until args.size) { println("$i: ${args[i]}") } for (i in args.indices) { println("$i: ${args[i]}") } for ((i, value) in args.withIndex()) { println("$i: $value}") }

Slide 62

Slide 62 text

No content

Slide 63

Slide 63 text

Destructuring declarations data class Person(val firstName: String, val lastName: String) val (name, age) = Person("Anton", "Arhipov")

Slide 64

Slide 64 text

Destructuring declarations data class Person(val firstName: String, val lastName: String) val p = Person("Anton", "Arhipov") val name = p.component1() val age = p.component2()

Slide 65

Slide 65 text

Destructuring: returning multiple values data class Result(val result: Int, val status: Status) fun function( ... ): Result { // computations return Result(result, status) } // Now, to use this function: val (result, status) = function( .. . )

Slide 66

Slide 66 text

Destructuring: iterating over a map for ((key, value) in map) { // do something with the key and the value }

Slide 67

Slide 67 text

Null-safety

Slide 68

Slide 68 text

Null-safety class Nullable { fun someFunction(){} } fun createNullable(): Nullable? = null fun main() { val n: Nullable? = createNullable() n.someFunction() }

Slide 69

Slide 69 text

Null-safety class Nullable { fun someFunction(){} } fun createNullable(): Nullable? = null fun main() { val n: Nullable? = createNullable() n.someFunction() }

Slide 70

Slide 70 text

Using null-safe call val order = retrieveOrder() if (order == null || order.customer = = null || order.customer.address == null){ throw IllegalArgumentException("Invalid Order") } val city = order.customer.address.city

Slide 71

Slide 71 text

Using null-safe call val order = retrieveOrder() if (order ?. customer ?. address == null){ throw IllegalArgumentException("Invalid Order") } val city = order.customer.address.city

Slide 72

Slide 72 text

Using null-safe call val order = retrieveOrder() val city = order ?. customer ?. address ?. city ?: throw IllegalArgumentException("Invalid Order")

Slide 73

Slide 73 text

Using null-safe call val order = retrieveOrder() val city = order ! ! .customer ! ! .address ! ! .city “You may notice that the double exclamation mark looks a bit rude: it’s almost like you’re yelling at the compiler. This is intentional.” - Kotlin in Action

Slide 74

Slide 74 text

Use lateinit instead of !! class MyTest { class State(val data: String) private var state: State? = null @BeforeEach fun setup() { state = State("abc") } @Test fun foo() { assertEquals("abc", state ! ! .data) } }

Slide 75

Slide 75 text

Use lateinit instead of !! class MyTest { class State(val data: String) private var state: State? = null @BeforeEach fun setup() { state = State("abc") } @Test fun foo() { assertEquals("abc", state ! ! .data) } } class MyTest { class State(val data: String) private lateinit var state: State @BeforeEach fun setup() { state = State("abc") } @Test fun foo() { assertEquals("abc", state.data) } }

Slide 76

Slide 76 text

No content

Slide 77

Slide 77 text

class Person(val name: String?, val age: Int?) val p = retrievePerson() ?: Person() Use elvis operator

Slide 78

Slide 78 text

class Person(val name: String?, val age: Int?) val p = retrievePerson() ?: Person() Use elvis operator

Slide 79

Slide 79 text

Use elvis operator as return and throw class Person(val name: String?, val age: Int?) fun processPerson(person: Person) { val name = person.name if (name = = null) throw IllegalArgumentException("Named required") val age = person.age if (age == null) return println("$name: $age") }

Slide 80

Slide 80 text

Use elvis operator as return and throw class Person(val name: String?, val age: Int?) fun processPerson(person: Person) { val name = person.name if (name = = null) throw IllegalArgumentException("Named required") val age = person.age if (age == null) return println("$name: $age") }

Slide 81

Slide 81 text

Use elvis operator as return and throw class Person(val name: String?, val age: Int?) fun processPerson(person: Person) { val name = person.name if (name = = null) throw IllegalArgumentException("Named required") val age = person.age if (age == null) return println("$name: $age") }

Slide 82

Slide 82 text

Use elvis operator as return and throw class Person(val name: String?, val age: Int?) fun processPerson(person: Person) { val name = person.name ? : throw IllegalArgumentException("Named required") val age = person.age ?: return println("$name: $age") }

Slide 83

Slide 83 text

Consider using safe cast for type checking override fun equals(other: Any?) : Boolean { val command = other as Command return command.id == id } override fun equals(other: Any?) : Boolean { return (other as? Command) ?. id == id } ‘as’ throws a ClassCastException on cast failure ‘as?’ returns null value on cast failure

Slide 84

Slide 84 text

Classes Properties Data classes Sealed classes Inline classes Objects Note to myself: show in the IDE

Slide 85

Slide 85 text

Collections Note to myself: show in the IDE

Slide 86

Slide 86 text

Java interoperability

Slide 87

Slide 87 text

No content

Slide 88

Slide 88 text

Standard library

Slide 89

Slide 89 text

Idiomatic Kotlin

Slide 90

Slide 90 text

Kotlin for backend development

Slide 91

Slide 91 text

Idiomatic Kotlin (writing DSL-like code)

Slide 92

Slide 92 text

Idiomatic - using, containing, or denoting expressions that are natural to a native speaker

Slide 93

Slide 93 text

Idiomatic - using, containing, or denoting expressions that are natural to a native speaker Commonly accepted style

Slide 94

Slide 94 text

Idiomatic - using, containing, or denoting expressions that are natural to a native speaker Commonly accepted style Effective use of features

Slide 95

Slide 95 text

No content

Slide 96

Slide 96 text

Domain Specific Languages DSL

Slide 97

Slide 97 text

External VS Internal

Slide 98

Slide 98 text

External VS Internal

Slide 99

Slide 99 text

External VS Internal

Slide 100

Slide 100 text

External VS Internal

Slide 101

Slide 101 text

External VS Internal

Slide 102

Slide 102 text

Internal

Slide 103

Slide 103 text

val name = "Joe" val s = buildString { repeat(5) { append("Hello, ") append(name) appendLine("!") } } println(s) String name = "Joe"; StringBuilder sb = new StringBuilder(); for (int i = 0; i < 5; i ++ ) { sb.append("Hello, "); sb.append(name); sb.append("!\n"); } System.out.println(sb); stdlib

Slide 104

Slide 104 text

System.out.appendHTML().html { body { div { a("http: // kotlinlang.org") { target = ATarget.blank +"Main site" } } } } kotlinx.html

Slide 105

Slide 105 text

kotlinx.html fun main() { embeddedServer(Netty, port = 8080, host = "0.0.0.0") { routing { get("/html-dsl") { call.respondHtml { body { h1 { +"HTML" } ul { for (n in 1 .. 10) { li { +"$n" } } } } } } } }.start(wait = true) }

Slide 106

Slide 106 text

kotlinx.html fun main() { embeddedServer(Netty, port = 8080, host = "0.0.0.0") { routing { get("/html-dsl") { call.respondHtml { body { h1 { +"HTML" } ul { for (n in 1 .. 10) { li { +"$n" } } } } } } } }.start(wait = true) } Ktor’s routing kotlinx.html

Slide 107

Slide 107 text

Let’s write some code! https://github.com/antonarhipov/kotlin-dsl-examples

Slide 108

Slide 108 text

Kotlin More presentations available on Kotlin channel youtube.com/kotlin Thanks for watching!