SlideShare a Scribd company logo
1 of 109
Download to read offline
@antonarhipov
Idiomatic Kotlin
from formatting to DSLs
Agenda
• Expressions

• Examples from standard library

• DSL
Anton Arhipov


@antonarhipov
Developer Advocate @ JetBrains
Idiomatic - using, containing, or denoting expressions
that are natural to a native speaker
Idiomatic - using, containing, or denoting expressions
that are natural to a native speaker
In case of a programming language:

•Conforms to a commonly accepted style

•E
ff
ectively uses features of the programming language
Expressions
try, if, when
fun adjustSpeed(weather: Weather): Drive {


var result: Drive


if (weather is Rainy) {


result = Safe()


} else {


result = Calm()


}




return result


}
fun adjustSpeed(weather: Weather): Drive {


var result: Drive


if (weather is Rainy) {


result = Safe()


} else {


result = Calm()


}




return result


}
fun adjustSpeed(weather: Weather): Drive {


val result: Drive


if (weather is Rainy) {


result = Safe()


} else {


result = Calm()


}




return result


}
fun adjustSpeed(weather: Weather): Drive {


val result: Drive


if (weather is Rainy) {


result = Safe()


} else {


result = Calm()


}




return result


}
fun adjustSpeed(weather: Weather): Drive {


val result: Drive


result = if (weather is Rainy) {


Safe()


} else {


Calm()


}


return result


}
fun adjustSpeed(weather: Weather): Drive {


val result: Drive


result = if (weather is Rainy) {


Safe()


} else {


Calm()


}


return result


}
fun adjustSpeed(weather: Weather): Drive {




val result: Drive = if (weather is Rainy) {


Safe()


} else {


Calm()


}


return result


}
fun adjustSpeed(weather: Weather): Drive {




val result: Drive = if (weather is Rainy) {


Safe()


} else {


Calm()


}


return result


}
fun adjustSpeed(weather: Weather): Drive {




return if (weather is Rainy) {


Safe()


} else {


Calm()


}


}
fun adjustSpeed(weather: Weather): Drive {




return if (weather is Rainy) {


Safe()


} else {


Calm()


}


}
fun adjustSpeed(weather: Weather): Drive = if (weather is Rainy) {


Safe()


} else {


Calm()


}
fun adjustSpeed(weather: Weather): Drive = if (weather is Rainy) {


Safe()


} else {


Calm()


}
fun adjustSpeed(weather: Weather) = if (weather is Rainy) {


Safe()


} else {


Calm()


}
fun adjustSpeed(weather: Weather) = if (weather is Rainy) {


Safe()


} else {


Calm()


}
fun adjustSpeed(weather: Weather) = if (weather is Rainy) Safe() else Calm()
fun adjustSpeed(weather: Weather) = if (weather is Rainy) Safe() else Calm()


fun adjustSpeed(weather: Weather): Drive {


var result: Drive


if (weather is Rainy) {


result = Safe()


} else {


result = Calm()


}




return result


}
fun adjustSpeed(weather: Weather) = if (weather is Rainy) Safe() else Calm()
fun adjustSpeed(weather: Weather) = if (weather is Rainy) Safe() else Calm()
abstract class Weather


class Sunny : Weather()


class Rainy : Weather()


fun adjustSpeed(weather: Weather) = when (weather) {


is Rainy
-
>
Safe()


else
-
>
Calm()


}
sealed class Weather


class Sunny : Weather()


class Rainy : Weather()


fun adjustSpeed(weather: Weather) = when (weather) {


is Rainy
-
>
Safe()


/
/
else
-
>
Calm()


}
sealed class Weather


class Sunny : Weather()


class Rainy : Weather()


fun adjustSpeed(weather: Weather) = when (weather) {


is Rainy
-
>
Safe()


/
/
else
-
>
Calm()


}
sealed class Weather


class Sunny : Weather()


class Rainy : Weather()


fun adjustSpeed(weather: Weather) = when (weather) {


is Rainy
-
>
Safe()


is Sunny
-
>
TODO()


}
sealed class Weather


class Sunny : Weather()


class Rainy : Weather()


fun adjustSpeed(weather: Weather) = when (weather) {


is Rainy
-
>
Safe()


is Sunny
-
>
TODO()


}


Use expressions!


Use when as expression body


Use sealed classes with when
Use try as expression body
fun tryParse(number: String) : Int? {


try {


return Integer.parseInt(number)


} catch (e: NumberFormatException) {


return null


}


}
Use try as expression body
fun tryParse(number: String) = try {


Integer.parseInt(number)


} catch (e: NumberFormatException) {


null


}
Use try as expression
fun tryParse(number: String) : Int? {


val n = try {


Integer.parseInt(number)


} catch (e: NumberFormatException) {


null


}


println(n)


return n


}
Use elvis operator
class Person(val name: String?, val age: Int?)


val p = retrievePerson()
?
:
Person()
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")


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


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


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


}
Nullability
Consider 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
Consider using null-safe call
val order = retrieveOrder()


val city = order
?
.
customer
?
.
address
?
.
city
Consider using null-safe call
val order = retrieveOrder()


val city = order
?
.
customer
?
.
address
?
.
city


?
:
throw IllegalArgumentException("Invalid Order")
Avoid not-null assertions !!
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
Avoid not-null assertions !!
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)


}


}
Avoid not-null assertions !!
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)


}


}
- use lateinit
Consider using ?.let for null-checks
val order = retrieveOrder()


if (order
!
=
null){


processCustomer(order.customer)


}
Consider using ?.let for null-checks
val order = retrieveOrder()


if (order
!
=
null){


processCustomer(order.customer)


}
retrieveOrder()
?
.
let {


processCustomer(it.customer)


}
retrieveOrder()
?
.
customer
?
.
let {
:
:
processCustomer }
or
Consider using ?.let for null-checks
val order = retrieveOrder()


if (order
!
=
null){


processCustomer(order.customer)


}
retrieveOrder()
?
.
let {


processCustomer(it.customer)


}
No need for an extra variable
retrieveOrder()
?
.
let {


processCustomer(it.customer)


}
retrieveOrder()
?
.
customer
?
.
let {
:
:
processCustomer }
or
Consider using ?.let for null-checks
val order = retrieveOrder()


if (order
!
=
null){


processCustomer(order.customer)


}
retrieveOrder()
?
.
let {


processCustomer(it.customer)


}
retrieveOrder()
?
.
let {


processCustomer(it.customer)


}
retrieveOrder()
?
.
customer
?
.
let {
:
:
processCustomer }
or
Consider using safe cast for type checking
override fun equals(other: Any?) : Boolean {


val command = other as Command


return command.id
=
=
id


}
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


}
Use range checks instead of comparison pairs
fun isLatinUppercase(c: Char) =


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


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


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


c in 'A'
.
.
'Z'
Ranges in loops
fun main(args: Array<String>) {




for (i in 0
.
.
args.size - 1) {


println("$i: ${args[i]}")


}




}
Ranges in loops
fun main(args: Array<String>) {




for (i in 0
.
.
args.size - 1) {


println("$i: ${args[i]}")


}




}
Ranges in loops
fun main(args: Array<String>) {




for (i in 0
.
.
args.size - 1) {


println("$i: ${args[i]}")


}




}


for (i in 0 until args.size) {


println("$i: ${args[i]}")


}
Ranges in loops
fun main(args: Array<String>) {




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


}
Ranges in loops
fun main(args: Array<String>) {




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, arg) in args.withIndex()) {


println("$i: $arg")


}
Classes and Functions
Don’t create classes just to hold functions
class StringUtils {


companion object {


fun isPhoneNumber(s: String) =


s.length
=
=
7
&
&
s.all { it.isDigit() }


}


}
Don’t create classes just to hold functions
class StringUtils {


companion object {


fun isPhoneNumber(s: String) =


s.length
=
=
7
&
&
s.all { it.isDigit() }


}


}


object StringUtils {


fun isPhoneNumber(s: String) =


s.length
=
=
7
&
&
s.all { it.isDigit() }


}
Don’t create classes just to hold functions
class StringUtils {


companion object {


fun isPhoneNumber(s: String) =


s.length
=
=
7
&
&
s.all { it.isDigit() }


}


}


object StringUtils {


fun isPhoneNumber(s: String) =


s.length
=
=
7
&
&
s.all { it.isDigit() }


}


fun isPhoneNumber(s: String) =


s.length
=
=
7
&
&
s.all { it.isDigit() }
Use extension functions
class StringUtils {


companion object {


fun isPhoneNumber(s: String) =


s.length
=
=
7
&
&
s.all { it.isDigit() }


}


}


object StringUtils {


fun isPhoneNumber(s: String) =


s.length
=
=
7
&
&
s.all { it.isDigit() }


}


fun isPhoneNumber(s: String) =


s.length
=
=
7
&
&
s.all { it.isDigit() }


fun String.isPhoneNumber() =


length
=
=
7
&
&
all { it.isDigit() }
Extension or a member?
https://kotlinlang.org/docs/coding-conventions.html#extension-functions
•Use extension functions liberally.
 

•If a function works primarily on an object, consider making it an
extension with that object as a receiver.
 

•Minimize API pollution, restrict the visibility.
 

•As necessary, use local extension functions, member extension
functions, or top-level extension functions with private visibility.
Use default values instead of overloading
class Phonebook {


fun print() {


print(",")


}


fun print(columnSeparator: String) {}


}


fun main(args: Array<String>) {


Phonebook().print("|")


}
Use default values instead of overloading
class Phonebook {


fun print() {


print(",")


}


fun print(columnSeparator: String) {}


}


fun main(args: Array<String>) {


Phonebook().print("|")


}


class Phonebook {


fun print(separator: String = ",") {}


fun someFun(x: Int) {}


}


fun main(args: Array<String>) {


Phonebook().print(separator = "|")


}
Return multiple values using data classes
fun namedNum(): Pair<Int, String> =


1 to "one"


/
/
same but shorter


fun namedNum2() = 1 to "one"


fun main(args: Array<String>) {


val pair = namedNum()


val number = pair.first


val name = pair.second


}
Return multiple values using data classes
fun namedNum(): Pair<Int, String> =


1 to "one"


/
/
same but shorter


fun namedNum2() = 1 to "one"


fun main(args: Array<String>) {


val pair = namedNum()


val number = pair.first


val name = pair.second


}
data class GameResult(


val rank: Int,


val name: String


)


fun namedNum() =


GameResult(1, "Player 1")


fun main(args: Array<String>) {


val (rank, name) = namedNum()


println("$name, rank $rank")


}
Return multiple values using data classes
data class GameResult(


val rank: Int,


val name: String


)


fun namedNum() =


GameResult(1, "Player 1")


fun main(args: Array<String>) {


val (rank, name) = namedNum()


println("$name, rank $rank")


}
GameResult var1 = namedNum();


int var2 = var1.component1();


String var3 = var1.component2();
Destructuring in loops
fun printMap(map: Map<String, String>) {


for (item in map.entries) {


println("${item.key}
-
>
${item.value}")


}


}
Destructuring in loops
fun printMap(map: Map<String, String>) {


for (item in map.entries) {


println("${item.key}
-
>
${item.value}")


}


}
fun printMap(map: Map<String, String>) {


for ((key, value) in map) {


println("$key
-
>
$value")


}


}
Destructuring in lists
data class NameExt(


val name: String,


val ext: String?


)


fun splitNameExt(filename: String): NameExt {


if ('.' in filename) {


val parts = filename.split('.', limit = 2)


return NameExt(parts[0], parts[1])


}


return NameExt(filename, null)


}


fun splitNameAndExtension(filename: String): NameExt {


if ('.' in filename) {


val (name, ext) = filename.split('.', limit = 2)


return NameExt(name, ext)


}


return NameExt(filename, null)


}
Use type aliases for functional types
class Event


class EventDispatcher {


fun addClickHandler(handler: (Event)
-
>
Unit) {}


fun removeClickHandler(handler: (Event)
-
>
Unit) {}


}
Use type aliases for functional types
class Event


class EventDispatcher {


fun addClickHandler(handler: (Event)
-
>
Unit) {}


fun removeClickHandler(handler: (Event)
-
>
Unit) {}


}
typealias ClickHandler = (Event)
-
>
Unit


class EventDispatcher {


fun addClickHandler(handler: ClickHandler) {


}


fun removeClickHandler(handler: ClickHandler) {


}


}
Standard Library
Verify parameters using require()
class Person(


val name: String?,


val age: Int


)


fun processPerson(person: Person) {


if (person.age < 18) {


throw IllegalArgumentException("Adult required")


}


}
Verify parameters using require()
class Person(


val name: String?,


val age: Int


)


fun processPerson(person: Person) {


if (person.age < 18) {


throw IllegalArgumentException("Adult required")


}


}


fun processPerson(person: Person) {


require(person.age
>
=
18) { "Adult required" }


}
Select objects by type with filterIsInstance
fun findAllStrings(objects: List<Any>) =


objects.filter { it is String }
Select objects by type with filterIsInstance
fun findAllStrings(objects: List<Any>) =


objects.filter { it is String }


fun findAllStrings(objects: List<Any>) =


objects.filterIsInstance<String>()
Select objects by type with filterIsInstance
fun findAllStrings(objects: List<Any>) : List<Any> =


objects.filter { it is String }


fun findAllStrings(objects: List<Any>) : List<String> =


objects.filterIsInstance<String>()
Apply operation to non-null elements mapNotNull
data class Result(


val data: Any?,


val error: String?


)


fun listErrors(results: List<Result>): List<String> =


results.map { it.error }.filterNotNull()


fun listErrors(results: List<Result>): List<String> =


results.mapNotNull { it.errorMessage }
compareBy compares by multiple keys
class Person(


val name: String,


val age: Int


)


fun sortPersons(persons: List<Person>) =


persons.sortedWith(Comparator<Person> { person1, person2
-
>


val rc = person1.name.compareTo(person2.name)


if (rc
!
=
0)


rc


else


person1.age - person2.age


})
compareBy compares by multiple keys
class Person(


val name: String,


val age: Int


)


fun sortPersons(persons: List<Person>) =


persons.sortedWith(Comparator<Person> { person1, person2
-
>


val rc = person1.name.compareTo(person2.name)


if (rc
!
=
0)


rc


else


person1.age - person2.age


})


fun sortPersons(persons: List<Person>) =


persons.sortedWith(compareBy(Person
:
:
name, Person
:
:
age))
groupBy to group elements
class Request(


val url: String,


val remoteIP: String,


val timestamp: Long


)


fun analyzeLog(log: List<Request>) {


val map = mutableMapOf<String, MutableList<Request
>
>
()


for (request in log) {


map.getOrPut(request.url) { mutableListOf() }


.add(request)


}


}
groupBy to group elements
class Request(


val url: String,


val remoteIP: String,


val timestamp: Long


)


fun analyzeLog(log: List<Request>) {


val map = mutableMapOf<String, MutableList<Request
>
>
()


for (request in log) {


map.getOrPut(request.url) { mutableListOf() }


.add(request)


}


}


fun analyzeLog(log: List<Request>) {


val map = log.groupBy(Request
:
:
url)


}
Use coerceIn to ensure numbers in range
fun updateProgress(value: Int) {


val actualValue = when {


value < 0
-
>
0


value > 100
-
>
100


else
-
>
value


}


}
fun updateProgress(value: Int) {


val actualValue = value.coerceIn(0, 100)


}
Initializing objects with apply
val dataSource = BasicDataSource(
)

dataSource.driverClassName = "com.mysql.jdbc.Driver"
dataSource.url = "jdbc:mysql://domain:3309/db"
dataSource.username = "username"
dataSource.password = "password"
dataSource.maxTotal = 40
dataSource.maxIdle = 40
dataSource.minIdle = 4
val dataSource = BasicDataSource().apply
{

driverClassName = "com.mysql.jdbc.Driver"
url = "jdbc:mysql://domain:3309/db"
username = "username"
password = "password"
maxTotal = 40
maxIdle = 40
minIdle = 4
}
Initializing objects with apply
final ClientBuilder builder = new ClientBuilder();


builder.setFirstName("Anton");


builder.setLastName("Arhipov");


final TwitterBuilder twitterBuilder = new TwitterBuilder();


twitterBuilder.setHandle("@antonarhipov");


builder.setTwitter(twitterBuilder.build());


final CompanyBuilder companyBuilder = new CompanyBuilder();


companyBuilder.setName("JetBrains");


companyBuilder.setCity("Tallinn");


builder.setCompany(companyBuilder.build());


final Client client = builder.build();


System.out.println("Created client is: " + client);
Initializing objects with apply
val builder = ClientBuilder()


builder.firstName = "Anton"


builder.lastName = "Arhipov"


val twitterBuilder = TwitterBuilder()


twitterBuilder.handle = "@antonarhipov"


builder.twitter = twitterBuilder.build()


val companyBuilder = CompanyBuilder()


companyBuilder.name = "JetBrains"


companyBuilder.city = "Tallinn"


builder.company = companyBuilder.build()


val client = builder.build()


println("Created client is: $client")
Initializing objects with apply
val builder = ClientBuilder()


builder.firstName = "Anton"


builder.lastName = "Arhipov"


val twitterBuilder = TwitterBuilder()


twitterBuilder.handle = "@antonarhipov"


builder.twitter = twitterBuilder.build()


val companyBuilder = CompanyBuilder()


companyBuilder.name = "JetBrains"


companyBuilder.city = "Tallinn"


builder.company = companyBuilder.build()


val client = builder.build()


println("Created client is: $client")


val client = ClientBuilder().apply {


firstName = "Anton"


lastName = "Arhipov"


twitter = TwitterBuilder().apply {


handle = "@antonarhipov"


}.build()


company = CompanyBuilder().apply {


name = "JetBrains"


city = "Tallinn"


}.build()


}.build()


println("Created client is: $client")
Domain Specific Languages
“Domain Speci
fi
c”,
i.e. tailored for a speci
fi
c task
“Domain Speci
fi
c”,
i.e. tailored for a speci
fi
c task
Examples:

•Compose strings - stringBuilder

•Create HTML documents - kotlinx.html

•Con
fi
gure routing logic for a web app - ktor

•Generally, build any object graphs. See “type-safe builders”
buildString
//Java
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);
//Kotlin
val name = "Joe"
val s = buildString {
repeat(5) {
append("Hello, ")
append(name)
appendLine("!")
}
}
println(s)
kotlinx.html
System.out.appendHTML().html {


body {


div {


a("http:
/
/
kotlinlang.org") {


target = ATarget.blank


+"Main site"


}


}


}


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


}


kotlinx.html
Ktor’s routing
Lambda with receiver
T.() -> Unit
Build your vocabulary to abstract from scope functions
val client = ClientBuilder().apply {


firstName = "Anton"


lastName = "Arhipov"


twitter = TwitterBuilder().apply {


handle = "@antonarhipov"


}.build()


company = CompanyBuilder().apply {


name = "JetBrains"


city = "Tallinn"


}.build()


}.build()


println("Created client is: $client")
Build your vocabulary to abstract from scope functions
fun client(c: ClientBuilder.()
-
>
Unit): Client {


val builder = ClientBuilder()


c(builder)


return builder.build()


}


fun ClientBuilder.company(block: CompanyBuilder.()
-
>
Unit) {


company = CompanyBuilder().apply(block).build()


}


fun ClientBuilder.twitter(block: TwitterBuilder.()
-
>
Unit) {


twitter = TwitterBuilder().apply(block).build()


}
val client = ClientBuilder().apply {


firstName = "Anton"


lastName = "Arhipov"


twitter = TwitterBuilder().apply {


handle = "@antonarhipov"


}.build()


company = CompanyBuilder().apply {


name = "JetBrains"


city = "Tallinn"


}.build()


}.build()


println("Created client is: $client")
val client = client {


firstName = "Anton"


lastName = "Arhipov"


twitter {


handle = "@antonarhipov"


}


company {


name = "JetBrains"


city = "Tallinn"


}


}


println("Created client is: $client")


Build your vocabulary to abstract from scope functions
val client = ClientBuilder().apply {


firstName = "Anton"


lastName = "Arhipov"


twitter = TwitterBuilder().apply {


handle = "@antonarhipov"


}.build()


company = CompanyBuilder().apply {


name = "JetBrains"


city = "Tallinn"


}.build()


}.build()


println("Created client is: $client")
https://speakerdeck.com/antonarhipov
https://github.com/antonarhipov/idiomatic-kotlin
@antonarhipov

More Related Content

What's hot

Railway Oriented Programming
Railway Oriented ProgrammingRailway Oriented Programming
Railway Oriented ProgrammingScott Wlaschin
 
Threads V4
Threads  V4Threads  V4
Threads V4Sunil OS
 
Introduction to kotlin coroutines
Introduction to kotlin coroutinesIntroduction to kotlin coroutines
Introduction to kotlin coroutinesNAVER Engineering
 
Kotlin Coroutines and Android sitting in a tree
Kotlin Coroutines and Android sitting in a treeKotlin Coroutines and Android sitting in a tree
Kotlin Coroutines and Android sitting in a treeKai Koenig
 
Java 8 - CJ
Java 8 - CJJava 8 - CJ
Java 8 - CJSunil OS
 
Kotlin Coroutines. Flow is coming
Kotlin Coroutines. Flow is comingKotlin Coroutines. Flow is coming
Kotlin Coroutines. Flow is comingKirill Rozov
 
Kotlin Coroutines Reloaded
Kotlin Coroutines ReloadedKotlin Coroutines Reloaded
Kotlin Coroutines ReloadedRoman Elizarov
 
Lock-free algorithms for Kotlin Coroutines
Lock-free algorithms for Kotlin CoroutinesLock-free algorithms for Kotlin Coroutines
Lock-free algorithms for Kotlin CoroutinesRoman Elizarov
 
If You Think You Can Stay Away from Functional Programming, You Are Wrong
If You Think You Can Stay Away from Functional Programming, You Are WrongIf You Think You Can Stay Away from Functional Programming, You Are Wrong
If You Think You Can Stay Away from Functional Programming, You Are WrongMario Fusco
 
Functional Design Patterns (DevTernity 2018)
Functional Design Patterns (DevTernity 2018)Functional Design Patterns (DevTernity 2018)
Functional Design Patterns (DevTernity 2018)Scott Wlaschin
 
The Power of Composition (NDC Oslo 2020)
The Power of Composition (NDC Oslo 2020)The Power of Composition (NDC Oslo 2020)
The Power of Composition (NDC Oslo 2020)Scott Wlaschin
 
Sequence and Traverse - Part 2
Sequence and Traverse - Part 2Sequence and Traverse - Part 2
Sequence and Traverse - Part 2Philip Schwarz
 
The Mighty Power of the Accessibility Service - Guy Griv, Pepper
The Mighty Power of the Accessibility Service - Guy Griv, PepperThe Mighty Power of the Accessibility Service - Guy Griv, Pepper
The Mighty Power of the Accessibility Service - Guy Griv, PepperDroidConTLV
 
Testing in-python-and-pytest-framework
Testing in-python-and-pytest-frameworkTesting in-python-and-pytest-framework
Testing in-python-and-pytest-frameworkArulalan T
 
JavaOne 2011 - JVM Bytecode for Dummies
JavaOne 2011 - JVM Bytecode for DummiesJavaOne 2011 - JVM Bytecode for Dummies
JavaOne 2011 - JVM Bytecode for DummiesCharles Nutter
 
Collections Framework
Collections FrameworkCollections Framework
Collections FrameworkSunil OS
 
JavaScript
JavaScriptJavaScript
JavaScriptSunil OS
 
DSU C&C++ Practical File Diploma
DSU C&C++ Practical File DiplomaDSU C&C++ Practical File Diploma
DSU C&C++ Practical File Diplomamustkeem khan
 

What's hot (20)

Railway Oriented Programming
Railway Oriented ProgrammingRailway Oriented Programming
Railway Oriented Programming
 
Threads V4
Threads  V4Threads  V4
Threads V4
 
Introduction to kotlin coroutines
Introduction to kotlin coroutinesIntroduction to kotlin coroutines
Introduction to kotlin coroutines
 
Kotlin Coroutines and Android sitting in a tree
Kotlin Coroutines and Android sitting in a treeKotlin Coroutines and Android sitting in a tree
Kotlin Coroutines and Android sitting in a tree
 
Java 8 - CJ
Java 8 - CJJava 8 - CJ
Java 8 - CJ
 
Kotlin Coroutines. Flow is coming
Kotlin Coroutines. Flow is comingKotlin Coroutines. Flow is coming
Kotlin Coroutines. Flow is coming
 
Kotlin Coroutines Reloaded
Kotlin Coroutines ReloadedKotlin Coroutines Reloaded
Kotlin Coroutines Reloaded
 
Lock-free algorithms for Kotlin Coroutines
Lock-free algorithms for Kotlin CoroutinesLock-free algorithms for Kotlin Coroutines
Lock-free algorithms for Kotlin Coroutines
 
If You Think You Can Stay Away from Functional Programming, You Are Wrong
If You Think You Can Stay Away from Functional Programming, You Are WrongIf You Think You Can Stay Away from Functional Programming, You Are Wrong
If You Think You Can Stay Away from Functional Programming, You Are Wrong
 
Functional Design Patterns (DevTernity 2018)
Functional Design Patterns (DevTernity 2018)Functional Design Patterns (DevTernity 2018)
Functional Design Patterns (DevTernity 2018)
 
F# for C# Programmers
F# for C# ProgrammersF# for C# Programmers
F# for C# Programmers
 
The Power of Composition (NDC Oslo 2020)
The Power of Composition (NDC Oslo 2020)The Power of Composition (NDC Oslo 2020)
The Power of Composition (NDC Oslo 2020)
 
Sequence and Traverse - Part 2
Sequence and Traverse - Part 2Sequence and Traverse - Part 2
Sequence and Traverse - Part 2
 
The Mighty Power of the Accessibility Service - Guy Griv, Pepper
The Mighty Power of the Accessibility Service - Guy Griv, PepperThe Mighty Power of the Accessibility Service - Guy Griv, Pepper
The Mighty Power of the Accessibility Service - Guy Griv, Pepper
 
Testing in-python-and-pytest-framework
Testing in-python-and-pytest-frameworkTesting in-python-and-pytest-framework
Testing in-python-and-pytest-framework
 
Zio in real world
Zio in real worldZio in real world
Zio in real world
 
JavaOne 2011 - JVM Bytecode for Dummies
JavaOne 2011 - JVM Bytecode for DummiesJavaOne 2011 - JVM Bytecode for Dummies
JavaOne 2011 - JVM Bytecode for Dummies
 
Collections Framework
Collections FrameworkCollections Framework
Collections Framework
 
JavaScript
JavaScriptJavaScript
JavaScript
 
DSU C&C++ Practical File Diploma
DSU C&C++ Practical File DiplomaDSU C&C++ Practical File Diploma
DSU C&C++ Practical File Diploma
 

Similar to Idiomatic kotlin

Scala vs Java 8 in a Java 8 World
Scala vs Java 8 in a Java 8 WorldScala vs Java 8 in a Java 8 World
Scala vs Java 8 in a Java 8 WorldBTI360
 
Exploring Koltin on Android
Exploring Koltin on AndroidExploring Koltin on Android
Exploring Koltin on AndroidDeepanshu Madan
 
Kotlin Basics - Apalon Kotlin Sprint Part 2
Kotlin Basics - Apalon Kotlin Sprint Part 2Kotlin Basics - Apalon Kotlin Sprint Part 2
Kotlin Basics - Apalon Kotlin Sprint Part 2Kirill Rozov
 
Swift - 혼자 공부하면 분명히 안할테니까 같이 공부하기
Swift - 혼자 공부하면 분명히 안할테니까 같이 공부하기Swift - 혼자 공부하면 분명히 안할테니까 같이 공부하기
Swift - 혼자 공부하면 분명히 안할테니까 같이 공부하기Suyeol Jeon
 
Kotlin Advanced - Apalon Kotlin Sprint Part 3
Kotlin Advanced - Apalon Kotlin Sprint Part 3Kotlin Advanced - Apalon Kotlin Sprint Part 3
Kotlin Advanced - Apalon Kotlin Sprint Part 3Kirill Rozov
 
Concurrent Application Development using Scala
Concurrent Application Development using ScalaConcurrent Application Development using Scala
Concurrent Application Development using ScalaSiarhiej Siemianchuk
 
Derping With Kotlin
Derping With KotlinDerping With Kotlin
Derping With KotlinRoss Tuck
 
Kotlinify Your Project!
Kotlinify Your Project!Kotlinify Your Project!
Kotlinify Your Project!OrNoyman
 
Introduction to Swift programming language.
Introduction to Swift programming language.Introduction to Swift programming language.
Introduction to Swift programming language.Icalia Labs
 
Parametricity - #cljsyd - May, 2015
Parametricity - #cljsyd - May, 2015Parametricity - #cljsyd - May, 2015
Parametricity - #cljsyd - May, 2015Leonardo Borges
 
A swift introduction to Swift
A swift introduction to SwiftA swift introduction to Swift
A swift introduction to SwiftGiordano Scalzo
 
Ast transformations
Ast transformationsAst transformations
Ast transformationsHamletDRC
 
Dip into Coroutines - KTUG Munich 202303
Dip into Coroutines - KTUG Munich 202303Dip into Coroutines - KTUG Munich 202303
Dip into Coroutines - KTUG Munich 202303Alex Semin
 
Why Scala is the better Java
Why Scala is the better JavaWhy Scala is the better Java
Why Scala is the better JavaThomas Kaiser
 
Functional Programming with Groovy
Functional Programming with GroovyFunctional Programming with Groovy
Functional Programming with GroovyArturo Herrero
 

Similar to Idiomatic kotlin (20)

Scala vs Java 8 in a Java 8 World
Scala vs Java 8 in a Java 8 WorldScala vs Java 8 in a Java 8 World
Scala vs Java 8 in a Java 8 World
 
Exploring Koltin on Android
Exploring Koltin on AndroidExploring Koltin on Android
Exploring Koltin on Android
 
Kotlin Basics - Apalon Kotlin Sprint Part 2
Kotlin Basics - Apalon Kotlin Sprint Part 2Kotlin Basics - Apalon Kotlin Sprint Part 2
Kotlin Basics - Apalon Kotlin Sprint Part 2
 
Swift - 혼자 공부하면 분명히 안할테니까 같이 공부하기
Swift - 혼자 공부하면 분명히 안할테니까 같이 공부하기Swift - 혼자 공부하면 분명히 안할테니까 같이 공부하기
Swift - 혼자 공부하면 분명히 안할테니까 같이 공부하기
 
Kotlin Advanced - Apalon Kotlin Sprint Part 3
Kotlin Advanced - Apalon Kotlin Sprint Part 3Kotlin Advanced - Apalon Kotlin Sprint Part 3
Kotlin Advanced - Apalon Kotlin Sprint Part 3
 
Concurrent Application Development using Scala
Concurrent Application Development using ScalaConcurrent Application Development using Scala
Concurrent Application Development using Scala
 
Derping With Kotlin
Derping With KotlinDerping With Kotlin
Derping With Kotlin
 
Kotlinify Your Project!
Kotlinify Your Project!Kotlinify Your Project!
Kotlinify Your Project!
 
SDC - Einführung in Scala
SDC - Einführung in ScalaSDC - Einführung in Scala
SDC - Einführung in Scala
 
Introduction to Swift programming language.
Introduction to Swift programming language.Introduction to Swift programming language.
Introduction to Swift programming language.
 
Introduction to Scala
Introduction to ScalaIntroduction to Scala
Introduction to Scala
 
Parametricity - #cljsyd - May, 2015
Parametricity - #cljsyd - May, 2015Parametricity - #cljsyd - May, 2015
Parametricity - #cljsyd - May, 2015
 
Pooya Khaloo Presentation on IWMC 2015
Pooya Khaloo Presentation on IWMC 2015Pooya Khaloo Presentation on IWMC 2015
Pooya Khaloo Presentation on IWMC 2015
 
A swift introduction to Swift
A swift introduction to SwiftA swift introduction to Swift
A swift introduction to Swift
 
Ast transformations
Ast transformationsAst transformations
Ast transformations
 
Dip into Coroutines - KTUG Munich 202303
Dip into Coroutines - KTUG Munich 202303Dip into Coroutines - KTUG Munich 202303
Dip into Coroutines - KTUG Munich 202303
 
Swift-Programming Part 1
Swift-Programming Part 1Swift-Programming Part 1
Swift-Programming Part 1
 
Why Scala is the better Java
Why Scala is the better JavaWhy Scala is the better Java
Why Scala is the better Java
 
Functional Programming with Groovy
Functional Programming with GroovyFunctional Programming with Groovy
Functional Programming with Groovy
 
Kotlin
KotlinKotlin
Kotlin
 

More from Anton Arhipov

JavaZone 2022 - Building Kotlin DSL.pdf
JavaZone 2022 - Building Kotlin DSL.pdfJavaZone 2022 - Building Kotlin DSL.pdf
JavaZone 2022 - Building Kotlin DSL.pdfAnton Arhipov
 
TechTrain 2019 - (Не)адекватное техническое интервью
TechTrain 2019 - (Не)адекватное техническое интервьюTechTrain 2019 - (Не)адекватное техническое интервью
TechTrain 2019 - (Не)адекватное техническое интервьюAnton Arhipov
 
Build pipelines with TeamCity
Build pipelines with TeamCityBuild pipelines with TeamCity
Build pipelines with TeamCityAnton Arhipov
 
Build pipelines with TeamCity
Build pipelines with TeamCityBuild pipelines with TeamCity
Build pipelines with TeamCityAnton Arhipov
 
Devoxx Ukraine 2018 - Kotlin DSL in under an hour
Devoxx Ukraine 2018 - Kotlin DSL in under an hourDevoxx Ukraine 2018 - Kotlin DSL in under an hour
Devoxx Ukraine 2018 - Kotlin DSL in under an hourAnton Arhipov
 
GeeCON Prague 2018 - Kotlin DSL in under an hour
GeeCON Prague 2018 - Kotlin DSL in under an hourGeeCON Prague 2018 - Kotlin DSL in under an hour
GeeCON Prague 2018 - Kotlin DSL in under an hourAnton Arhipov
 
Build pipelines with TeamCity and Kotlin DSL
Build pipelines with TeamCity and Kotlin DSLBuild pipelines with TeamCity and Kotlin DSL
Build pipelines with TeamCity and Kotlin DSLAnton Arhipov
 
Build pipelines with TeamCity
Build pipelines with TeamCityBuild pipelines with TeamCity
Build pipelines with TeamCityAnton Arhipov
 
JavaDay Kiev 2017 - Integration testing with TestContainers
JavaDay Kiev 2017 - Integration testing with TestContainersJavaDay Kiev 2017 - Integration testing with TestContainers
JavaDay Kiev 2017 - Integration testing with TestContainersAnton Arhipov
 
GeeCON Prague 2017 - TestContainers
GeeCON Prague 2017 - TestContainersGeeCON Prague 2017 - TestContainers
GeeCON Prague 2017 - TestContainersAnton Arhipov
 
JavaOne 2017 - The hitchhiker’s guide to Java class reloading
JavaOne 2017 - The hitchhiker’s guide to Java class reloadingJavaOne 2017 - The hitchhiker’s guide to Java class reloading
JavaOne 2017 - The hitchhiker’s guide to Java class reloadingAnton Arhipov
 
JavaOne 2017 - TestContainers: integration testing without the hassle
JavaOne 2017 - TestContainers: integration testing without the hassleJavaOne 2017 - TestContainers: integration testing without the hassle
JavaOne 2017 - TestContainers: integration testing without the hassleAnton Arhipov
 
JavaOne 2017 - The hitchhiker’s guide to Java class reloading
JavaOne 2017 - The hitchhiker’s guide to Java class reloadingJavaOne 2017 - The hitchhiker’s guide to Java class reloading
JavaOne 2017 - The hitchhiker’s guide to Java class reloadingAnton Arhipov
 
JavaZone 2017 - The Hitchhiker’s guide to Java class reloading
JavaZone 2017 - The Hitchhiker’s guide to Java class reloadingJavaZone 2017 - The Hitchhiker’s guide to Java class reloading
JavaZone 2017 - The Hitchhiker’s guide to Java class reloadingAnton Arhipov
 
JUG.ua 20170225 - Java bytecode instrumentation
JUG.ua 20170225 - Java bytecode instrumentationJUG.ua 20170225 - Java bytecode instrumentation
JUG.ua 20170225 - Java bytecode instrumentationAnton Arhipov
 
Riga DevDays 2017 - The hitchhiker’s guide to Java class reloading
Riga DevDays 2017 - The hitchhiker’s guide to Java class reloadingRiga DevDays 2017 - The hitchhiker’s guide to Java class reloading
Riga DevDays 2017 - The hitchhiker’s guide to Java class reloadingAnton Arhipov
 
GeeCON 2017 - TestContainers. Integration testing without the hassle
GeeCON 2017 - TestContainers. Integration testing without the hassleGeeCON 2017 - TestContainers. Integration testing without the hassle
GeeCON 2017 - TestContainers. Integration testing without the hassleAnton Arhipov
 
JEEConf 2017 - The hitchhiker’s guide to Java class reloading
JEEConf 2017 - The hitchhiker’s guide to Java class reloadingJEEConf 2017 - The hitchhiker’s guide to Java class reloading
JEEConf 2017 - The hitchhiker’s guide to Java class reloadingAnton Arhipov
 
JEEConf 2017 - Having fun with Javassist
JEEConf 2017 - Having fun with JavassistJEEConf 2017 - Having fun with Javassist
JEEConf 2017 - Having fun with JavassistAnton Arhipov
 
Devclub 01/2017 - (Не)адекватное Java-интервью
Devclub 01/2017 - (Не)адекватное Java-интервьюDevclub 01/2017 - (Не)адекватное Java-интервью
Devclub 01/2017 - (Не)адекватное Java-интервьюAnton Arhipov
 

More from Anton Arhipov (20)

JavaZone 2022 - Building Kotlin DSL.pdf
JavaZone 2022 - Building Kotlin DSL.pdfJavaZone 2022 - Building Kotlin DSL.pdf
JavaZone 2022 - Building Kotlin DSL.pdf
 
TechTrain 2019 - (Не)адекватное техническое интервью
TechTrain 2019 - (Не)адекватное техническое интервьюTechTrain 2019 - (Не)адекватное техническое интервью
TechTrain 2019 - (Не)адекватное техническое интервью
 
Build pipelines with TeamCity
Build pipelines with TeamCityBuild pipelines with TeamCity
Build pipelines with TeamCity
 
Build pipelines with TeamCity
Build pipelines with TeamCityBuild pipelines with TeamCity
Build pipelines with TeamCity
 
Devoxx Ukraine 2018 - Kotlin DSL in under an hour
Devoxx Ukraine 2018 - Kotlin DSL in under an hourDevoxx Ukraine 2018 - Kotlin DSL in under an hour
Devoxx Ukraine 2018 - Kotlin DSL in under an hour
 
GeeCON Prague 2018 - Kotlin DSL in under an hour
GeeCON Prague 2018 - Kotlin DSL in under an hourGeeCON Prague 2018 - Kotlin DSL in under an hour
GeeCON Prague 2018 - Kotlin DSL in under an hour
 
Build pipelines with TeamCity and Kotlin DSL
Build pipelines with TeamCity and Kotlin DSLBuild pipelines with TeamCity and Kotlin DSL
Build pipelines with TeamCity and Kotlin DSL
 
Build pipelines with TeamCity
Build pipelines with TeamCityBuild pipelines with TeamCity
Build pipelines with TeamCity
 
JavaDay Kiev 2017 - Integration testing with TestContainers
JavaDay Kiev 2017 - Integration testing with TestContainersJavaDay Kiev 2017 - Integration testing with TestContainers
JavaDay Kiev 2017 - Integration testing with TestContainers
 
GeeCON Prague 2017 - TestContainers
GeeCON Prague 2017 - TestContainersGeeCON Prague 2017 - TestContainers
GeeCON Prague 2017 - TestContainers
 
JavaOne 2017 - The hitchhiker’s guide to Java class reloading
JavaOne 2017 - The hitchhiker’s guide to Java class reloadingJavaOne 2017 - The hitchhiker’s guide to Java class reloading
JavaOne 2017 - The hitchhiker’s guide to Java class reloading
 
JavaOne 2017 - TestContainers: integration testing without the hassle
JavaOne 2017 - TestContainers: integration testing without the hassleJavaOne 2017 - TestContainers: integration testing without the hassle
JavaOne 2017 - TestContainers: integration testing without the hassle
 
JavaOne 2017 - The hitchhiker’s guide to Java class reloading
JavaOne 2017 - The hitchhiker’s guide to Java class reloadingJavaOne 2017 - The hitchhiker’s guide to Java class reloading
JavaOne 2017 - The hitchhiker’s guide to Java class reloading
 
JavaZone 2017 - The Hitchhiker’s guide to Java class reloading
JavaZone 2017 - The Hitchhiker’s guide to Java class reloadingJavaZone 2017 - The Hitchhiker’s guide to Java class reloading
JavaZone 2017 - The Hitchhiker’s guide to Java class reloading
 
JUG.ua 20170225 - Java bytecode instrumentation
JUG.ua 20170225 - Java bytecode instrumentationJUG.ua 20170225 - Java bytecode instrumentation
JUG.ua 20170225 - Java bytecode instrumentation
 
Riga DevDays 2017 - The hitchhiker’s guide to Java class reloading
Riga DevDays 2017 - The hitchhiker’s guide to Java class reloadingRiga DevDays 2017 - The hitchhiker’s guide to Java class reloading
Riga DevDays 2017 - The hitchhiker’s guide to Java class reloading
 
GeeCON 2017 - TestContainers. Integration testing without the hassle
GeeCON 2017 - TestContainers. Integration testing without the hassleGeeCON 2017 - TestContainers. Integration testing without the hassle
GeeCON 2017 - TestContainers. Integration testing without the hassle
 
JEEConf 2017 - The hitchhiker’s guide to Java class reloading
JEEConf 2017 - The hitchhiker’s guide to Java class reloadingJEEConf 2017 - The hitchhiker’s guide to Java class reloading
JEEConf 2017 - The hitchhiker’s guide to Java class reloading
 
JEEConf 2017 - Having fun with Javassist
JEEConf 2017 - Having fun with JavassistJEEConf 2017 - Having fun with Javassist
JEEConf 2017 - Having fun with Javassist
 
Devclub 01/2017 - (Не)адекватное Java-интервью
Devclub 01/2017 - (Не)адекватное Java-интервьюDevclub 01/2017 - (Не)адекватное Java-интервью
Devclub 01/2017 - (Не)адекватное Java-интервью
 

Recently uploaded

How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonetsnaman860154
 
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 3652toLead Limited
 
Azure Monitor & Application Insight to monitor Infrastructure & Application
Azure Monitor & Application Insight to monitor Infrastructure & ApplicationAzure Monitor & Application Insight to monitor Infrastructure & Application
Azure Monitor & Application Insight to monitor Infrastructure & ApplicationAndikSusilo4
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdfhans926745
 
AI as an Interface for Commercial Buildings
AI as an Interface for Commercial BuildingsAI as an Interface for Commercial Buildings
AI as an Interface for Commercial BuildingsMemoori
 
How to Remove Document Management Hurdles with X-Docs?
How to Remove Document Management Hurdles with X-Docs?How to Remove Document Management Hurdles with X-Docs?
How to Remove Document Management Hurdles with X-Docs?XfilesPro
 
Enhancing Worker Digital Experience: A Hands-on Workshop for Partners
Enhancing Worker Digital Experience: A Hands-on Workshop for PartnersEnhancing Worker Digital Experience: A Hands-on Workshop for Partners
Enhancing Worker Digital Experience: A Hands-on Workshop for PartnersThousandEyes
 
Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...Alan Dix
 
Pigging Solutions Piggable Sweeping Elbows
Pigging Solutions Piggable Sweeping ElbowsPigging Solutions Piggable Sweeping Elbows
Pigging Solutions Piggable Sweeping ElbowsPigging Solutions
 
Key Features Of Token Development (1).pptx
Key  Features Of Token  Development (1).pptxKey  Features Of Token  Development (1).pptx
Key Features Of Token Development (1).pptxLBM Solutions
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024Rafal Los
 
Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...
Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...
Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...HostedbyConfluent
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationRadu Cotescu
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationMichael W. Hawkins
 
Understanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitectureUnderstanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitecturePixlogix Infotech
 
SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024Scott Keck-Warren
 
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Patryk Bandurski
 
My Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationMy Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationRidwan Fadjar
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking MenDelhi Call girls
 
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...shyamraj55
 

Recently uploaded (20)

How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonets
 
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
 
Azure Monitor & Application Insight to monitor Infrastructure & Application
Azure Monitor & Application Insight to monitor Infrastructure & ApplicationAzure Monitor & Application Insight to monitor Infrastructure & Application
Azure Monitor & Application Insight to monitor Infrastructure & Application
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf
 
AI as an Interface for Commercial Buildings
AI as an Interface for Commercial BuildingsAI as an Interface for Commercial Buildings
AI as an Interface for Commercial Buildings
 
How to Remove Document Management Hurdles with X-Docs?
How to Remove Document Management Hurdles with X-Docs?How to Remove Document Management Hurdles with X-Docs?
How to Remove Document Management Hurdles with X-Docs?
 
Enhancing Worker Digital Experience: A Hands-on Workshop for Partners
Enhancing Worker Digital Experience: A Hands-on Workshop for PartnersEnhancing Worker Digital Experience: A Hands-on Workshop for Partners
Enhancing Worker Digital Experience: A Hands-on Workshop for Partners
 
Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...
 
Pigging Solutions Piggable Sweeping Elbows
Pigging Solutions Piggable Sweeping ElbowsPigging Solutions Piggable Sweeping Elbows
Pigging Solutions Piggable Sweeping Elbows
 
Key Features Of Token Development (1).pptx
Key  Features Of Token  Development (1).pptxKey  Features Of Token  Development (1).pptx
Key Features Of Token Development (1).pptx
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024
 
Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...
Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...
Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organization
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day Presentation
 
Understanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitectureUnderstanding the Laravel MVC Architecture
Understanding the Laravel MVC Architecture
 
SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024
 
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
 
My Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationMy Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 Presentation
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men
 
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
 

Idiomatic kotlin

  • 2. Agenda • Expressions • Examples from standard library • DSL
  • 4.
  • 5.
  • 6.
  • 7. Idiomatic - using, containing, or denoting expressions that are natural to a native speaker
  • 8. Idiomatic - using, containing, or denoting expressions that are natural to a native speaker In case of a programming language: •Conforms to a commonly accepted style •E ff ectively uses features of the programming language
  • 9.
  • 11. fun adjustSpeed(weather: Weather): Drive { var result: Drive if (weather is Rainy) { result = Safe() } else { result = Calm() } return result }
  • 12. fun adjustSpeed(weather: Weather): Drive { var result: Drive if (weather is Rainy) { result = Safe() } else { result = Calm() } return result }
  • 13. fun adjustSpeed(weather: Weather): Drive { val result: Drive if (weather is Rainy) { result = Safe() } else { result = Calm() } return result }
  • 14. fun adjustSpeed(weather: Weather): Drive { val result: Drive if (weather is Rainy) { result = Safe() } else { result = Calm() } return result }
  • 15. fun adjustSpeed(weather: Weather): Drive { val result: Drive result = if (weather is Rainy) { Safe() } else { Calm() } return result }
  • 16. fun adjustSpeed(weather: Weather): Drive { val result: Drive result = if (weather is Rainy) { Safe() } else { Calm() } return result }
  • 17. fun adjustSpeed(weather: Weather): Drive { val result: Drive = if (weather is Rainy) { Safe() } else { Calm() } return result }
  • 18. fun adjustSpeed(weather: Weather): Drive { val result: Drive = if (weather is Rainy) { Safe() } else { Calm() } return result }
  • 19. fun adjustSpeed(weather: Weather): Drive { return if (weather is Rainy) { Safe() } else { Calm() } }
  • 20. fun adjustSpeed(weather: Weather): Drive { return if (weather is Rainy) { Safe() } else { Calm() } }
  • 21. fun adjustSpeed(weather: Weather): Drive = if (weather is Rainy) { Safe() } else { Calm() }
  • 22. fun adjustSpeed(weather: Weather): Drive = if (weather is Rainy) { Safe() } else { Calm() }
  • 23. fun adjustSpeed(weather: Weather) = if (weather is Rainy) { Safe() } else { Calm() }
  • 24. fun adjustSpeed(weather: Weather) = if (weather is Rainy) { Safe() } else { Calm() }
  • 25. fun adjustSpeed(weather: Weather) = if (weather is Rainy) Safe() else Calm()
  • 26. fun adjustSpeed(weather: Weather) = if (weather is Rainy) Safe() else Calm() fun adjustSpeed(weather: Weather): Drive { var result: Drive if (weather is Rainy) { result = Safe() } else { result = Calm() } return result }
  • 27. fun adjustSpeed(weather: Weather) = if (weather is Rainy) Safe() else Calm()
  • 28. fun adjustSpeed(weather: Weather) = if (weather is Rainy) Safe() else Calm()
  • 29. abstract class Weather class Sunny : Weather() class Rainy : Weather() fun adjustSpeed(weather: Weather) = when (weather) { is Rainy - > Safe() else - > Calm() }
  • 30. sealed class Weather class Sunny : Weather() class Rainy : Weather() fun adjustSpeed(weather: Weather) = when (weather) { is Rainy - > Safe() / / else - > Calm() }
  • 31. sealed class Weather class Sunny : Weather() class Rainy : Weather() fun adjustSpeed(weather: Weather) = when (weather) { is Rainy - > Safe() / / else - > Calm() }
  • 32. sealed class Weather class Sunny : Weather() class Rainy : Weather() fun adjustSpeed(weather: Weather) = when (weather) { is Rainy - > Safe() is Sunny - > TODO() }
  • 33. sealed class Weather class Sunny : Weather() class Rainy : Weather() fun adjustSpeed(weather: Weather) = when (weather) { is Rainy - > Safe() is Sunny - > TODO() } Use expressions! Use when as expression body Use sealed classes with when
  • 34. Use try as expression body fun tryParse(number: String) : Int? { try { return Integer.parseInt(number) } catch (e: NumberFormatException) { return null } }
  • 35. Use try as expression body fun tryParse(number: String) = try { Integer.parseInt(number) } catch (e: NumberFormatException) { null }
  • 36. Use try as expression fun tryParse(number: String) : Int? { val n = try { Integer.parseInt(number) } catch (e: NumberFormatException) { null } println(n) return n }
  • 37. Use elvis operator class Person(val name: String?, val age: Int?) val p = retrievePerson() ? : Person()
  • 38. 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") }
  • 39. 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") }
  • 40. 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") }
  • 41. 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") }
  • 43. Consider 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
  • 44. Consider using null-safe call val order = retrieveOrder() val city = order ? . customer ? . address ? . city
  • 45. Consider using null-safe call val order = retrieveOrder() val city = order ? . customer ? . address ? . city ? : throw IllegalArgumentException("Invalid Order")
  • 46. Avoid not-null assertions !! 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
  • 47. Avoid not-null assertions !! 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) } }
  • 48. Avoid not-null assertions !! 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) } } - use lateinit
  • 49. Consider using ?.let for null-checks val order = retrieveOrder() if (order ! = null){ processCustomer(order.customer) }
  • 50. Consider using ?.let for null-checks val order = retrieveOrder() if (order ! = null){ processCustomer(order.customer) } retrieveOrder() ? . let { processCustomer(it.customer) } retrieveOrder() ? . customer ? . let { : : processCustomer } or
  • 51. Consider using ?.let for null-checks val order = retrieveOrder() if (order ! = null){ processCustomer(order.customer) } retrieveOrder() ? . let { processCustomer(it.customer) } No need for an extra variable retrieveOrder() ? . let { processCustomer(it.customer) } retrieveOrder() ? . customer ? . let { : : processCustomer } or
  • 52. Consider using ?.let for null-checks val order = retrieveOrder() if (order ! = null){ processCustomer(order.customer) } retrieveOrder() ? . let { processCustomer(it.customer) } retrieveOrder() ? . let { processCustomer(it.customer) } retrieveOrder() ? . customer ? . let { : : processCustomer } or
  • 53. Consider using safe cast for type checking override fun equals(other: Any?) : Boolean { val command = other as Command return command.id = = id }
  • 54. 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 }
  • 55. Use range checks instead of comparison pairs fun isLatinUppercase(c: Char) = c > = 'A' & & c < = 'Z'
  • 56. Use range checks instead of comparison pairs fun isLatinUppercase(c: Char) = c > = 'A' & & c < = 'Z'
  • 57. Use range checks instead of comparison pairs fun isLatinUppercase(c: Char) = c in 'A' . . 'Z'
  • 58. Use range checks instead of comparison pairs fun isLatinUppercase(c: Char) = c in 'A' . . 'Z'
  • 59. Ranges in loops fun main(args: Array<String>) { for (i in 0 . . args.size - 1) { println("$i: ${args[i]}") } }
  • 60. Ranges in loops fun main(args: Array<String>) { for (i in 0 . . args.size - 1) { println("$i: ${args[i]}") } }
  • 61. Ranges in loops fun main(args: Array<String>) { for (i in 0 . . args.size - 1) { println("$i: ${args[i]}") } } for (i in 0 until args.size) { println("$i: ${args[i]}") }
  • 62. Ranges in loops fun main(args: Array<String>) { 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]}") }
  • 63. Ranges in loops fun main(args: Array<String>) { 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, arg) in args.withIndex()) { println("$i: $arg") }
  • 65. Don’t create classes just to hold functions class StringUtils { companion object { fun isPhoneNumber(s: String) = s.length = = 7 & & s.all { it.isDigit() } } }
  • 66. Don’t create classes just to hold functions class StringUtils { companion object { fun isPhoneNumber(s: String) = s.length = = 7 & & s.all { it.isDigit() } } } object StringUtils { fun isPhoneNumber(s: String) = s.length = = 7 & & s.all { it.isDigit() } }
  • 67. Don’t create classes just to hold functions class StringUtils { companion object { fun isPhoneNumber(s: String) = s.length = = 7 & & s.all { it.isDigit() } } } object StringUtils { fun isPhoneNumber(s: String) = s.length = = 7 & & s.all { it.isDigit() } } fun isPhoneNumber(s: String) = s.length = = 7 & & s.all { it.isDigit() }
  • 68. Use extension functions class StringUtils { companion object { fun isPhoneNumber(s: String) = s.length = = 7 & & s.all { it.isDigit() } } } object StringUtils { fun isPhoneNumber(s: String) = s.length = = 7 & & s.all { it.isDigit() } } fun isPhoneNumber(s: String) = s.length = = 7 & & s.all { it.isDigit() } fun String.isPhoneNumber() = length = = 7 & & all { it.isDigit() }
  • 69. Extension or a member? https://kotlinlang.org/docs/coding-conventions.html#extension-functions •Use extension functions liberally. •If a function works primarily on an object, consider making it an extension with that object as a receiver. •Minimize API pollution, restrict the visibility. •As necessary, use local extension functions, member extension functions, or top-level extension functions with private visibility.
  • 70. Use default values instead of overloading class Phonebook { fun print() { print(",") } fun print(columnSeparator: String) {} } fun main(args: Array<String>) { Phonebook().print("|") }
  • 71. Use default values instead of overloading class Phonebook { fun print() { print(",") } fun print(columnSeparator: String) {} } fun main(args: Array<String>) { Phonebook().print("|") } class Phonebook { fun print(separator: String = ",") {} fun someFun(x: Int) {} } fun main(args: Array<String>) { Phonebook().print(separator = "|") }
  • 72. Return multiple values using data classes fun namedNum(): Pair<Int, String> = 1 to "one" / / same but shorter fun namedNum2() = 1 to "one" fun main(args: Array<String>) { val pair = namedNum() val number = pair.first val name = pair.second }
  • 73. Return multiple values using data classes fun namedNum(): Pair<Int, String> = 1 to "one" / / same but shorter fun namedNum2() = 1 to "one" fun main(args: Array<String>) { val pair = namedNum() val number = pair.first val name = pair.second } data class GameResult( val rank: Int, val name: String ) fun namedNum() = GameResult(1, "Player 1") fun main(args: Array<String>) { val (rank, name) = namedNum() println("$name, rank $rank") }
  • 74. Return multiple values using data classes data class GameResult( val rank: Int, val name: String ) fun namedNum() = GameResult(1, "Player 1") fun main(args: Array<String>) { val (rank, name) = namedNum() println("$name, rank $rank") } GameResult var1 = namedNum(); int var2 = var1.component1(); String var3 = var1.component2();
  • 75. Destructuring in loops fun printMap(map: Map<String, String>) { for (item in map.entries) { println("${item.key} - > ${item.value}") } }
  • 76. Destructuring in loops fun printMap(map: Map<String, String>) { for (item in map.entries) { println("${item.key} - > ${item.value}") } } fun printMap(map: Map<String, String>) { for ((key, value) in map) { println("$key - > $value") } }
  • 77. Destructuring in lists data class NameExt( val name: String, val ext: String? ) fun splitNameExt(filename: String): NameExt { if ('.' in filename) { val parts = filename.split('.', limit = 2) return NameExt(parts[0], parts[1]) } return NameExt(filename, null) } fun splitNameAndExtension(filename: String): NameExt { if ('.' in filename) { val (name, ext) = filename.split('.', limit = 2) return NameExt(name, ext) } return NameExt(filename, null) }
  • 78.
  • 79. Use type aliases for functional types class Event class EventDispatcher { fun addClickHandler(handler: (Event) - > Unit) {} fun removeClickHandler(handler: (Event) - > Unit) {} }
  • 80. Use type aliases for functional types class Event class EventDispatcher { fun addClickHandler(handler: (Event) - > Unit) {} fun removeClickHandler(handler: (Event) - > Unit) {} } typealias ClickHandler = (Event) - > Unit class EventDispatcher { fun addClickHandler(handler: ClickHandler) { } fun removeClickHandler(handler: ClickHandler) { } }
  • 82. Verify parameters using require() class Person( val name: String?, val age: Int ) fun processPerson(person: Person) { if (person.age < 18) { throw IllegalArgumentException("Adult required") } }
  • 83. Verify parameters using require() class Person( val name: String?, val age: Int ) fun processPerson(person: Person) { if (person.age < 18) { throw IllegalArgumentException("Adult required") } } fun processPerson(person: Person) { require(person.age > = 18) { "Adult required" } }
  • 84. Select objects by type with filterIsInstance fun findAllStrings(objects: List<Any>) = objects.filter { it is String }
  • 85. Select objects by type with filterIsInstance fun findAllStrings(objects: List<Any>) = objects.filter { it is String } fun findAllStrings(objects: List<Any>) = objects.filterIsInstance<String>()
  • 86. Select objects by type with filterIsInstance fun findAllStrings(objects: List<Any>) : List<Any> = objects.filter { it is String } fun findAllStrings(objects: List<Any>) : List<String> = objects.filterIsInstance<String>()
  • 87. Apply operation to non-null elements mapNotNull data class Result( val data: Any?, val error: String? ) fun listErrors(results: List<Result>): List<String> = results.map { it.error }.filterNotNull() fun listErrors(results: List<Result>): List<String> = results.mapNotNull { it.errorMessage }
  • 88. compareBy compares by multiple keys class Person( val name: String, val age: Int ) fun sortPersons(persons: List<Person>) = persons.sortedWith(Comparator<Person> { person1, person2 - > val rc = person1.name.compareTo(person2.name) if (rc ! = 0) rc else person1.age - person2.age })
  • 89. compareBy compares by multiple keys class Person( val name: String, val age: Int ) fun sortPersons(persons: List<Person>) = persons.sortedWith(Comparator<Person> { person1, person2 - > val rc = person1.name.compareTo(person2.name) if (rc ! = 0) rc else person1.age - person2.age }) fun sortPersons(persons: List<Person>) = persons.sortedWith(compareBy(Person : : name, Person : : age))
  • 90. groupBy to group elements class Request( val url: String, val remoteIP: String, val timestamp: Long ) fun analyzeLog(log: List<Request>) { val map = mutableMapOf<String, MutableList<Request > > () for (request in log) { map.getOrPut(request.url) { mutableListOf() } .add(request) } }
  • 91. groupBy to group elements class Request( val url: String, val remoteIP: String, val timestamp: Long ) fun analyzeLog(log: List<Request>) { val map = mutableMapOf<String, MutableList<Request > > () for (request in log) { map.getOrPut(request.url) { mutableListOf() } .add(request) } } fun analyzeLog(log: List<Request>) { val map = log.groupBy(Request : : url) }
  • 92. Use coerceIn to ensure numbers in range fun updateProgress(value: Int) { val actualValue = when { value < 0 - > 0 value > 100 - > 100 else - > value } } fun updateProgress(value: Int) { val actualValue = value.coerceIn(0, 100) }
  • 93. Initializing objects with apply val dataSource = BasicDataSource( ) dataSource.driverClassName = "com.mysql.jdbc.Driver" dataSource.url = "jdbc:mysql://domain:3309/db" dataSource.username = "username" dataSource.password = "password" dataSource.maxTotal = 40 dataSource.maxIdle = 40 dataSource.minIdle = 4 val dataSource = BasicDataSource().apply { driverClassName = "com.mysql.jdbc.Driver" url = "jdbc:mysql://domain:3309/db" username = "username" password = "password" maxTotal = 40 maxIdle = 40 minIdle = 4 }
  • 94. Initializing objects with apply final ClientBuilder builder = new ClientBuilder(); builder.setFirstName("Anton"); builder.setLastName("Arhipov"); final TwitterBuilder twitterBuilder = new TwitterBuilder(); twitterBuilder.setHandle("@antonarhipov"); builder.setTwitter(twitterBuilder.build()); final CompanyBuilder companyBuilder = new CompanyBuilder(); companyBuilder.setName("JetBrains"); companyBuilder.setCity("Tallinn"); builder.setCompany(companyBuilder.build()); final Client client = builder.build(); System.out.println("Created client is: " + client);
  • 95. Initializing objects with apply val builder = ClientBuilder() builder.firstName = "Anton" builder.lastName = "Arhipov" val twitterBuilder = TwitterBuilder() twitterBuilder.handle = "@antonarhipov" builder.twitter = twitterBuilder.build() val companyBuilder = CompanyBuilder() companyBuilder.name = "JetBrains" companyBuilder.city = "Tallinn" builder.company = companyBuilder.build() val client = builder.build() println("Created client is: $client")
  • 96. Initializing objects with apply val builder = ClientBuilder() builder.firstName = "Anton" builder.lastName = "Arhipov" val twitterBuilder = TwitterBuilder() twitterBuilder.handle = "@antonarhipov" builder.twitter = twitterBuilder.build() val companyBuilder = CompanyBuilder() companyBuilder.name = "JetBrains" companyBuilder.city = "Tallinn" builder.company = companyBuilder.build() val client = builder.build() println("Created client is: $client") val client = ClientBuilder().apply { firstName = "Anton" lastName = "Arhipov" twitter = TwitterBuilder().apply { handle = "@antonarhipov" }.build() company = CompanyBuilder().apply { name = "JetBrains" city = "Tallinn" }.build() }.build() println("Created client is: $client")
  • 98. “Domain Speci fi c”, i.e. tailored for a speci fi c task
  • 99. “Domain Speci fi c”, i.e. tailored for a speci fi c task Examples: •Compose strings - stringBuilder •Create HTML documents - kotlinx.html •Con fi gure routing logic for a web app - ktor •Generally, build any object graphs. See “type-safe builders”
  • 100. buildString //Java 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); //Kotlin val name = "Joe" val s = buildString { repeat(5) { append("Hello, ") append(name) appendLine("!") } } println(s)
  • 101. kotlinx.html System.out.appendHTML().html { body { div { a("http: / / kotlinlang.org") { target = ATarget.blank +"Main site" } } } }
  • 102. Ktor 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) }
  • 103. Ktor 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
  • 104. Ktor 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) } kotlinx.html Ktor’s routing
  • 106. Build your vocabulary to abstract from scope functions val client = ClientBuilder().apply { firstName = "Anton" lastName = "Arhipov" twitter = TwitterBuilder().apply { handle = "@antonarhipov" }.build() company = CompanyBuilder().apply { name = "JetBrains" city = "Tallinn" }.build() }.build() println("Created client is: $client")
  • 107. Build your vocabulary to abstract from scope functions fun client(c: ClientBuilder.() - > Unit): Client { val builder = ClientBuilder() c(builder) return builder.build() } fun ClientBuilder.company(block: CompanyBuilder.() - > Unit) { company = CompanyBuilder().apply(block).build() } fun ClientBuilder.twitter(block: TwitterBuilder.() - > Unit) { twitter = TwitterBuilder().apply(block).build() } val client = ClientBuilder().apply { firstName = "Anton" lastName = "Arhipov" twitter = TwitterBuilder().apply { handle = "@antonarhipov" }.build() company = CompanyBuilder().apply { name = "JetBrains" city = "Tallinn" }.build() }.build() println("Created client is: $client")
  • 108. val client = client { firstName = "Anton" lastName = "Arhipov" twitter { handle = "@antonarhipov" } company { name = "JetBrains" city = "Tallinn" } } println("Created client is: $client") Build your vocabulary to abstract from scope functions val client = ClientBuilder().apply { firstName = "Anton" lastName = "Arhipov" twitter = TwitterBuilder().apply { handle = "@antonarhipov" }.build() company = CompanyBuilder().apply { name = "JetBrains" city = "Tallinn" }.build() }.build() println("Created client is: $client")