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