Slide 1

Slide 1 text

Kotlin 2.0, 2.1, and beyond @antonarhipov

Slide 2

Slide 2 text

No content

Slide 3

Slide 3 text

History before Kotlin 2.0

Slide 4

Slide 4 text

July 20, 2011 - Kotlin announced at JVMLS February 15, 2016 - Kotlin 1.0 May 21, 2024 - Kotlin 2.0

Slide 5

Slide 5 text

July 20, 2011 - Kotlin announced at JVMLS February 15, 2016 - Kotlin 1.0 May 21, 2024 - Kotlin 2.0 "A general purpose, statically typed, object-oriented alternative JVM programming language with type inference"

Slide 6

Slide 6 text

July 20, 2011 - Kotlin announced at JVMLS February 15, 2016 - Kotlin 1.0 May 21, 2024 - Kotlin 2.0

Slide 7

Slide 7 text

July 20, 2011 - Kotlin announced at JVMLS February 15, 2016 - Kotlin 1.0 May 21, 2024 - Kotlin 2.0

Slide 8

Slide 8 text

July 20, 2011 - Kotlin announced at JVMLS February 15, 2016 - Kotlin 1.0 May 21, 2024 - Kotlin 2.0 1.1, 1.2, 1.3, 1.4, 1.5, 1.6.x, 1.7.x, 1.8.x, 1.9.x

Slide 9

Slide 9 text

July 20, 2011 - Kotlin announced at JVMLS February 15, 2016 - Kotlin 1.0 2019 May 21, 2024 - Kotlin 2.0 (with K2 ) May 2025 ( ?) - Kotlin 2.2 Work star t ed on the new compiler front-end (K2 )

Slide 10

Slide 10 text

July 20, 2011 - Kotlin announced at JVMLS February 15, 2016 - Kotlin 1.0 May 21, 2024 - Kotlin 2.0

Slide 11

Slide 11 text

July 20, 2011 - Kotlin announced at JVMLS February 15, 2016 - Kotlin 1.0 May 21, 2024 - Kotlin 2.0 November 27, 2024 - Kotlin 2.1 May 2025 ( ?) - Kotlin 2.2

Slide 12

Slide 12 text

My favourite Kotlin features A very subjective view

Slide 13

Slide 13 text

data class Person( val name: String, val age: Int ) It used to be very easy to create the wow effect with this: public class Person { private final String name; private final int age; public Person(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public int getAge() { return age; } @Override public boolean equals(Object o) { if (this = = o) return true; if (o == null | | getClass() ! = o.getClass()) return false; Person person = (Person) o; if (age != person.age) return false; return name != null ? name.equals(person.name) : person.name == null; } @Override public int hashCode() { int result = name != null ? name.hashCode() : 0; result = 31 * result + age; return result; } @Override public String toString() { return "Person{" + "name='" + name + '\'' + ", age=" + age + '}'; } }

Slide 14

Slide 14 text

data class Person( val name: String, val age: Int ) But now Java has records . public record Person( String name, int age ) {}

Slide 15

Slide 15 text

Kotlin still has a lot to offer:

Slide 16

Slide 16 text

fun main() { val event = "Devoxx" println("Hello, $event!") } Very simple to star t !

Slide 17

Slide 17 text

fun main() { val event = "Devoxx" println("Hello, $event!") } String templates

Slide 18

Slide 18 text

fun main() { val event = "Devoxx" println("Hello, ${event.uppercase()}!") } String templates with expressions

Slide 19

Slide 19 text

fun main() { val event = "Devoxx" println("Hello, ${event.uppercase()}!") println("Hello, ${event.randomCase()}!") } fun String.randomCase(chance: Double = 0.5): String { return map { if (Math.random() < chance) it.uppercaseChar() else it.lowercaseChar() }.joinToString("") } Top-level functions

Slide 20

Slide 20 text

fun main() { val event = "Devoxx" println("Hello, ${event.uppercase()}!") println("Hello, ${event.randomCase()}!") } fun String.randomCase(chance: Double = 0.5): String { return map { if (Math.random() < chance) it.uppercaseChar() else it.lowercaseChar() }.joinToString("") } Extension functions!

Slide 21

Slide 21 text

fun main() { val event = "Devoxx" println("Hello, ${event.uppercase()}!") println("Hello, ${event.randomCase()}!") } fun String.randomCase(chance: Double = 0.5): String = map { if (Math.random() < chance) it.uppercaseChar() else it.lowercaseChar() }.joinToString("") } Single-expression functions!!

Slide 22

Slide 22 text

fun main() { val event = "Devoxx" println("Hello, ${event.uppercase()}!") println("Hello, ${event.randomCase()}!") } fun String.randomCase(chance: Double = 0.5) = map { if (Math.random() < chance) it.uppercaseChar() else it.lowercaseChar() }.joinToString("") } Type inference!!!

Slide 23

Slide 23 text

fun main() { val event = "Devoxx" println("Hello, ${event.uppercase()}!") println("Hello, ${event.randomCase()}!") } fun String.randomCase(chance: Double = 0.5) = map { if (Math.random() < chance) it.uppercaseChar() else it.lowercaseChar() }.joinToString("") } Default argument values

Slide 24

Slide 24 text

fun main() { val event = "Devoxx" println("Hello, ${event.uppercase()}!") println("Hello, ${event.randomCase(offset = 0.25)}!") } fun String.randomCase(chance: Double = 0.5, offset: Double = 0.1) = map { if (Math.random() < chance) it.uppercaseChar() else it.lowercaseChar() }.joinToString("") } Named parameters

Slide 25

Slide 25 text

fun main() { val event = "Devoxx" println("Hello, ${event.uppercase()}!") println("Hello, ${event.randomCase(offset = 0.25)}!") println("Hello, ${event.transform { it.randomCase(offset = 0.25) }} !") } fun String.transform(transformer: (String) -> String) = transformer(this) Trailing lambda as a parameter

Slide 26

Slide 26 text

fun main() { val event: String? = getEventName() println("Hello, ${event.uppercase()}!") println("Hello, ${event.randomCase(offset = 0.25)}!") } private fun getEventName(): String? = "Devoxx" Nullable types

Slide 27

Slide 27 text

fun main() { val event: String? = getEventName() println("Hello, ${event ? . uppercase()}!") println("Hello, ${event ! ! .randomCase(offset = 0.25)}!") } private fun getEventName(): String? = "Devoxx" Operators for working with null values

Slide 28

Slide 28 text

Kotlin still has a lot to offer: These features combined make a huge difference in how we reason about the code and structure Kotlin programs

Slide 29

Slide 29 text

Features added after Kotlin 1.0 : - Multiplatform projects - Coroutines - Inline / Value classes - Trailing comma - fun inter f aces - .

Slide 30

Slide 30 text

Features added after Kotlin 1.0 : - Multiplatform projects - Coroutines - Inline / Value classes - Trailing comma - fun inter f aces - Type aliases - Sealed classes & inter f aces - Contracts - break/continue inside when - Exhaustive when statements - Builder inference - . . < operator - Data objects

Slide 31

Slide 31 text

Features added after Kotlin 1.0 : - Multiplatform projects - Coroutines - Inline / Value classes - Trailing comma - fun inter f aces - Type aliases - Sealed classes & inter f aces - Contracts - break/continue inside when - Exhaustive when statements - Builder inference - ..< operator - Data objects - provideDelegate - Bound callable references - Destructuring in lambdas - Array literals in annotations - Local lateinit variables - Opt-in annotations - Definitely non-nullable types - Instantiation of annotation classes - Suppor t for JSpecify - suspend functions as super t ypes - Secondary constructors for inline value classes A LOT

Slide 32

Slide 32 text

Technical debt strikes back

Slide 33

Slide 33 text

K2 Fighting technical debt

Slide 34

Slide 34 text

K2 : The new Kotlin compiler - why?

Slide 35

Slide 35 text

K2 : The new Kotlin compiler - why? "K1 was a prototype" - someone

Slide 36

Slide 36 text

K2 : The new Kotlin compiler - why? 1. A few language features have appeared unexpectedly in Kotlin Hard to maintain and evolve the compiler 2. Interaction with compiler and IDEs Many ad-hoc solutions, no strict contracts, and no stable API 3. Compilation time per f ormance

Slide 37

Slide 37 text

K2 : The new Kotlin compiler - why? 1. A few language features have appeared unexpectedly in Kotlin Hard to maintain and evolve the compiler 2. Interaction with compiler and IDEs Many ad-hoc solutions, no strict contracts, and no stable API 3. Compilation time per f ormance

Slide 38

Slide 38 text

K2 : The new Kotlin compiler - why? 1. A few language features have appeared unexpectedly in Kotlin Hard to maintain and evolve the compiler 2. Interaction with compiler and IDEs Many ad-hoc solutions, no strict contracts, and no stable API 3. Compilation time per f ormance

Slide 39

Slide 39 text

K1 K2 Kotlin ecosystem

Slide 40

Slide 40 text

Kotlin 2.0 More than 80 features in the different subsystems Around 25 and small improvements within the language Main focus is on correctness and per f ormance

Slide 41

Slide 41 text

Frontend Backend Cat.kt Cat.class IR

Slide 42

Slide 42 text

Frontend Kotlin/JVM Cat.kt Cat.class IR

Slide 43

Slide 43 text

Frontend Kotlin/JVM Cat.kt Cat.class IR Kotlin/Native Kotlin/Wasm Kotlin/JS Native binaries *.wasm *.js

Slide 44

Slide 44 text

Kotlin/JVM Cat.kt IR Kotlin/Native Kotlin/Wasm Kotlin/JS Analyzer Parser FIR

Slide 45

Slide 45 text

Kotlin/JVM Cat.kt IR Kotlin/Native Kotlin/Wasm Kotlin/JS Analyzer Parser FIR Frontend Intermediate Representation

Slide 46

Slide 46 text

Frontend Intermediate Representation (FIR)

Slide 47

Slide 47 text

if (condition) { println("Hello") } when { condition -> println("Hello") } Frontend Intermediate Representation (FIR)

Slide 48

Slide 48 text

if (condition) { println("Hello") } when { condition -> println("Hello") } for (n in list) { println(n) } val = list.interator() while(.hasNext()){ val s = .next() println(s) } Frontend Intermediate Representation (FIR)

Slide 49

Slide 49 text

if (condition) { println("Hello") } when { condition -> println("Hello") } for (n in list) { println(n) } val = list.interator() while(.hasNext()){ val s = .next() println(s) } val (a, b) = "a" to "b" val = "a" to "b" val a = pair.component1() val b = pair.component2() Frontend Intermediate Representation (FIR)

Slide 50

Slide 50 text

fun mutate(ml: MutableList) { ml[0] = ml[0] + 1 } Combination of Long and Integer Literal Types Frontend Intermediate Representation (FIR)

Slide 51

Slide 51 text

fun mutate(ml: MutableList) { ml[0] = ml[0] + 1 } Combination of Long and Integer Literal Types Long Integer Literal Type Frontend Intermediate Representation (FIR)

Slide 52

Slide 52 text

fun mutate(ml: MutableList) { ml[0] += 1 } Combination of Long and Integer Literal Types Error: 1L is required // Error in Kotlin 1.x Frontend Intermediate Representation (FIR)

Slide 53

Slide 53 text

fun mutate(ml: MutableList) { ml[0] += 1 } Combination of Long and Integer Literal Types // OK in 2.0 Desugared into: ml.set(0, ml.get(0).plus(1)) Frontend Intermediate Representation (FIR)

Slide 54

Slide 54 text

Combination of nullable operator-calls class Box(val ml: MutableList) fun mutate(box: Box?) { box ?. ml[0] += 1 // Error in 1.x box ?. ml[0] += 1L // Error in 1.x } Frontend Intermediate Representation (FIR)

Slide 55

Slide 55 text

Combination of nullable operator-calls class Box(val ml: MutableList) fun mutate(box: Box?) { box ?. ml[0] += 1 // OK in 2.0 } box ?. run { ml.set(0, ml.get(0).plus(1))} Desugared into: Frontend Intermediate Representation (FIR)

Slide 56

Slide 56 text

New control flow engine read: more smar t -casts! - KT-7186 Smar t cast for captured variables inside changing closures of inline functions - KT-4113 Smar t casts for proper t ies to not-null functional types at invoke calls - KT-25747 DFA variables: propagate smar t cast results from local variables - KT-1982 Smar t cast to a common super t ype of subject types after || (OR operator) - .

Slide 57

Slide 57 text

Smart-casts

Slide 58

Slide 58 text

class Cat { fun purr() { println("Purr purr") } } fun petAnimal(animal: Any) { if (animal is Cat) { animal.purr() } } Smart-casts

Slide 59

Slide 59 text

class Cat { fun purr() { println("Purr purr") } } fun petAnimal(animal: Any) { if (animal is Cat) { animal.purr() } } Smart-casts

Slide 60

Slide 60 text

class Cat { fun purr() { println("Purr purr") } } fun petAnimal(animal: Any) { val isCat = animal is Cat if (isCat) { animal.purr() // Error in Kotlin 1.x } } Smart-casts from variables

Slide 61

Slide 61 text

class Cat { fun purr() { println("Purr purr") } } fun petAnimal(animal: Any) { val isCat = animal is Cat if (isCat) { animal.purr() // Error in Kotlin 1.x } } Smart-casts from variables Kotlin 1.x: variables don't carry any data fl ow information

Slide 62

Slide 62 text

class Cat { fun purr() { println("Purr purr") } } fun petAnimal(animal: Any) { val isCat = animal is Cat if (isCat) { animal.purr() // OK in Kotlin 2.0 } } Smart-casts from variables Kotlin 2.0: synthetic data fl ow variables propagate information about smart-casts

Slide 63

Slide 63 text

Smart-casts from variables class Card(val holder: String?) fun findHolder(card: Any): String { val cardWithHolder = card is Card && !card.holder.isNullOrEmpty() return when { cardWithHolder -> { card.holder } else -> "none" } }

Slide 64

Slide 64 text

Smart-casts from variables class Card(val holder: String?) fun findHolder(card: Any): String { val cardWithHolder = card is Card && !card.holder.isNullOrEmpty() return when { cardWithHolder -> { card.holder } else -> "none" } }

Slide 65

Slide 65 text

Smart-casts from variables class Card(val holder: String?) fun findHolder(card: Any): String { val cardWithHolder = card is Card && !card.holder.isNullOrEmpty() return when { cardWithHolder -> { card.holder } else -> "none" } } Any -> Card Smart-casted to Card

Slide 66

Slide 66 text

Smart-casts from variables class Card(val holder: String?) fun findHolder(card: Any): String { val cardWithHolder = card is Card && !card.holder.isNullOrEmpty() return when { cardWithHolder -> { card.holder } else -> "none" } } Any -> Card String? -> String Smart-casted to String Smart-casted to Card

Slide 67

Slide 67 text

This slide is intentionally left blank

Slide 68

Slide 68 text

What's next for Kotlin?

Slide 69

Slide 69 text

What's next for Kotlin? Guards: pattern matching without binding Name-based destructuring Union types for errors Context parameters Effect system capabilities (Contracts) ... and more

Slide 70

Slide 70 text

What's next for Kotlin? Guards: pattern matching without binding - 2.1 Name-based destructuring - 2.2 Union types for errors - 2.x Context parameters - 2.2 Effect system capabilities (Contracts) ... and more

Slide 71

Slide 71 text

when { order is YearlySubscription && order.amount > 100 -> applyDiscount(order) order is MonthlySubscription -> startSubscription(order) order is OneTimeOrder -> processOrder(order) } val order = getOrder()

Slide 72

Slide 72 text

when { order is YearlySubscription && order.amount > 100 -> applyDiscount(order) order is MonthlySubscription -> startSubscription(order) order is OneTimeOrder -> processOrder(order) } val order = getOrder() Potentially a logical error Repetition is not nice

Slide 73

Slide 73 text

when { order is YearlySubscription && order.amount > 100 -> applyDiscount(order) order is YearlySubscription -> processSubscription(order) order is MonthlySubscription -> startSubscription(order) order is OneTimeOrder -> processOrder(order) } val order = getOrder()

Slide 74

Slide 74 text

when(order) { is YearlySubscription && order.amount > 100 -> applyDiscount(order) is YearlySubscription -> processSubscription(order) is MonthlySubscription -> startSubscription(order) is OneTimeOrder -> processOrder(order) } val order = getOrder()

Slide 75

Slide 75 text

when(order) { is YearlySubscription && order.amount > 100 -> applyDiscount(order) is YearlySubscription -> processSubscription(order) is MonthlySubscription -> startSubscription(order) is OneTimeOrder -> processOrder(order) } val order = getOrder() Error: expecting ' -> ' &&

Slide 76

Slide 76 text

when(order) { is YearlySubscription && order.amount > 100 -> applyDiscount(order) is YearlySubscription -> processSubscription(order) is MonthlySubscription -> startSubscription(order) is OneTimeOrder -> processOrder(order) } val order = getOrder() Guarded conditions: KEEP - 371 if

Slide 77

Slide 77 text

when(order) { is YearlySubscription if order.amount > 100 -> applyDiscount(order) is YearlySubscription -> processSubscription(order) is MonthlySubscription -> startSubscription(order) is OneTimeOrder -> processOrder(order) } val order = getOrder()

Slide 78

Slide 78 text

when(order) { is YearlySubscription -> processSubscription(order) is YearlySubscription if order.amount > 100 -> applyDiscount(order) is MonthlySubscription -> startSubscription(order) is OneTimeOrder -> processOrder(order) } val order = getOrder() 'when' branch is never reachable

Slide 79

Slide 79 text

when(order) { is YearlySubscription if order.amount > 100 -> applyDiscount(order) is YearlySubscription -> processSubscription(order) is MonthlySubscription -> startSubscription(order) is OneTimeOrder -> processOrder(order) } val order = getOrder() 2.1

Slide 80

Slide 80 text

when(order) { is YearlySubscription if order.amount > 100 -> { val (id, name, amount) = order println("Order $id: $name $amount") } is YearlySubscription -> processSubscription(order) ... val order = getOrder() Destructuring

Slide 81

Slide 81 text

when(order) { is YearlySubscription if order.amount > 100 -> { val (id, name, amount) = order println("Order $id: $name $amount") } is YearlySubscription -> processSubscription(order) ... val order = YearlySubscription("1", "Anton", 12.0, 2024 OCTOBER 9) Destructuring Order 1: Anton, 12.0

Slide 82

Slide 82 text

when(order) { is YearlySubscription if order.amount > 100 -> { val (name, id, amount) = order println("Order $id: $name $amount") } is YearlySubscription -> processSubscription(order) ... val order = YearlySubscription("1", "Anton", 12.0, 2024 OCTOBER 9) Variable name 'id' matches the name of a different component Destructuring

Slide 83

Slide 83 text

when(order) { is YearlySubscription if order.amount > 100 -> { val (name, id, amount) = order println("Order $id: $name $amount") } is YearlySubscription -> processSubscription(order) ... val order = YearlySubscription("1", "Anton", 12.0, 2024 OCTOBER 9) Order Anton: 1, 12.0 Destructuring

Slide 84

Slide 84 text

when(order) { is YearlySubscription if order.amount > 100 -> { val (name, id, amount) = order println("Order $id: $name $amount") } is YearlySubscription -> processSubscription(order) ... val order = YearlySubscription("1", "Anton", 12.0, 2024 OCTOBER 9) Error in 2.x: 'name' doesn’t match the property 'customerName' Name-based destructuring

Slide 85

Slide 85 text

What's next for Kotlin? Guards: pattern matching without binding - 2.1 Name-based destructuring - 2.2 Union types for errors - 2.x Context parameters - 2.2 Effect system capabilities (Contracts) ... and more

Slide 86

Slide 86 text

Find last matching element in the sequence orders.last { it.amount > threshold }

Slide 87

Slide 87 text

/** * Returns the last element matching the given [predicate]. */ public inline fun Sequence.last(predicate: (T) -> Boolean): T { var result: T? = null for (element in this) if (predicate(element)) result = element return result ? : throw NoSuchElementException("Not found") } Find last matching element in the sequence orders.last { it.amount > threshold }

Slide 88

Slide 88 text

What if the predicate is '{ it == null }' /** * Returns the last element matching the given [predicate]. */ public inline fun Sequence.last(predicate: (T) -> Boolean): T { var last: T? = null var found = false for (element in this) { if (predicate(element)) { last = element found = true } } if (!found) throw NoSuchElementException("Not found") @Suppress("UNCHECKED_CAST") return last as T }

Slide 89

Slide 89 text

private object NotFound fun Sequence.last(predicate: (T) -> Boolean): T { var result: Any? = NotFound for (element in this) if (predicate(element)) result = element if (result == = NotFound) throw NoSuchElementException("Not found") return result as T } Can we do better?

Slide 90

Slide 90 text

private object NotFound fun Sequence.last(predicate: (T) -> Boolean): T { var result: Any? = NotFound for (element in this) if (predicate(element)) result = element if (result == = NotFound) throw NoSuchElementException("Not found") return result as T } Use of 'Any?' type Unchecked cast Can we do better?

Slide 91

Slide 91 text

Union types for errors private error object NotFound fun Sequence.last(predicate: (T) -> Boolean): T { var result: T | NotFound = NotFound for (element in this) if (predicate(element)) result = element if (result is NotFound) throw NoSuchElementException("Not found") return result } Union types for errors Automatic smar t -cast In research

Slide 92

Slide 92 text

What's next for Kotlin? Guards: pattern matching without binding - 2.1 Name-based destructuring - 2.2 Union types for errors - 2.x Context parameters - 2.2 Effect system capabilities (Contracts) ... and more

Slide 93

Slide 93 text

class Client(var name: String? = null, var birthday: LocalDate? = null) fun buildClient(init: Client.() - > Unit): Client { var client = Client() client.init() return client } Use case: type-safe builders (a.k.a DSLs)

Slide 94

Slide 94 text

class Client(var name: String? = null, var birthday: LocalDate? = null) fun buildClient(init: Client.() - > Unit): Client { var client = Client() client.init() return client } Use case: type-safe builders DSL library

Slide 95

Slide 95 text

class Client(var name: String? = null, var birthday: LocalDate? = null) fun buildClient(init: Client.() - > Unit): Client { var client = Client() client.init() return client } Use case: type-safe builders DSL library buildClient { name = "Bob" birthday = LocalDate.of(2000, 3, 10) } User code

Slide 96

Slide 96 text

class Client(var name: String? = null, var birthday: LocalDate? = null) fun buildClient(init: Client.() - > Unit): Client { var client = Client() client.init() return client } Use case: type-safe builders DSL library buildClient { name = "Bob" birthday = LocalDate.of(2000, 3, 10) } User code Can we do better?

Slide 97

Slide 97 text

class Client(var name: String? = null, var birthday: LocalDate? = null) fun buildClient(init: Client.() - > Unit): Client { var client = Client() client.init() return client } Use case: type-safe builders DSL library buildClient { name = "Bob" birthday = 10 March 2000 } User code infix fun Int.March(year: Int) = LocalDate.of(year, Month.MARCH, this) val dob = 10 March 2000

Slide 98

Slide 98 text

class Client(var name: String? = null, var birthday: LocalDate? = null) fun buildClient(init: Client.() - > Unit): Client { var client = Client() client.init() return client } Use case: type-safe builders DSL library buildClient { name = "Bob" birthday = 10 March 2000 } User code infix fun Int.March(year: Int) = LocalDate.of(year, Month.MARCH, this) val dob = 10 March 2000 How can we restrict the scope?

Slide 99

Slide 99 text

object ClientBuilderContext context(_: ClientBuilderContext) infix fun Int.March(year: Int) = LocalDate.of(year, Month.MARCH, this) DSL library buildClient { name = "Bob" birthday = 10 March 2000 } User code val dob = 10 March 2000 Context parameters (KEEP - 367 )

Slide 100

Slide 100 text

DSL library buildClient { name = "Bob" birthday = 10 March 2000 } User code val dob = 10 March 2000 fun buildClient(init: context(ClientBuilderContext) Client.() - > Unit): Client = with(ClientBuilderContext()) { //. .. } object ClientBuilderContext context(_: ClientBuilderContext) infix fun Int.March(year: Int) = LocalDate.of(year, Month.MARCH, this) Context parameters (KEEP - 367 )

Slide 101

Slide 101 text

DSL library buildClient { name = "Bob" birthday = 10 March 2000 } User code val dob = 10 March 2000 fun buildClient(init: context(ClientBuilderContext) Client.() - > Unit): Client = with(ClientBuilderContext()) { //. .. } object ClientBuilderContext context(_: ClientBuilderContext) infix fun Int.March(year: Int) = LocalDate.of(year, Month.MARCH, this) Context parameters (KEEP - 367 )

Slide 102

Slide 102 text

DSL library buildClient { name = "Bob" birthday = 10 March 2000 } User code val dob = 10 March 2000 fun buildClient(init: context(ClientBuilderContext) Client.() - > Unit): Client = with(ClientBuilderContext()) { //. .. } object ClientBuilderContext context(_: ClientBuilderContext) infix fun Int.March(year: Int) = LocalDate.of(year, Month.MARCH, this) The required context is missing Required context available in this block Context parameters (KEEP - 367 )

Slide 103

Slide 103 text

What's next for Kotlin? Guards: pattern matching without binding - 2.1 Name-based destructuring - 2.2 Union types for errors - 2.x Context parameters - 2.2 Effect system capabilities (Contracts) ... and more

Slide 104

Slide 104 text

buildClient { name = "Bob" birthday = 10 March 2000 } Looks per f ect! Or isn't? .

Slide 105

Slide 105 text

buildClient { name = "Bob" // 'name' property stays uninitialized birthday = 10 March 2000 } Or ... What if the user forgets to assign a proper t y?

Slide 106

Slide 106 text

Effect system capabilities (or Contracts?) buildClient { name = "Bob" birthday = 10 March 2000 } This feature doesn't exist

Slide 107

Slide 107 text

Effect system capabilities buildClient { name = "Bob" birthday = 10 March 2000 } In research

Slide 108

Slide 108 text

Effect system capabilities buildClient { name = "Bob" birthday = 10 March 2000 } fun buildClient(init: Client.() - > Unit): Client { contract { called(init@name, ONCE) called(init@birthday, ONCE) } / /... } In research

Slide 109

Slide 109 text

Effect system capabilities buildClient { name = "Bob" birthday = 10 March 2000 } fun buildClient(init: Client.() - > Unit): Client { contract { called(init@name, ONCE) called(init@birthday, ONCE) } / /... } In research

Slide 110

Slide 110 text

Effect system capabilities buildClient { name = "Bob" birthday = 10 March 2000 } fun buildClient(init: Client.() - > Unit): Client { contract { called(init@name, ONCE) called(init@birthday, ONCE) } / /... } In research Contract: "Ensure that the 'name' proper t y is assigned once in the 'init' block"

Slide 111

Slide 111 text

Summary Kotlin 2.0 : new compiler & more smar t -casts More features are coming for working with data Stronger abstractions and improvements in the type system

Slide 112

Slide 112 text

https://speakerdeck.com/antonarhipov @antonarhipov https://github.com/antonarhipov https://youtube.com/kotlin