SlideShare a Scribd company logo
@antonarhipov
Idiomatic Kotlin
from formatting to DSLs
Agenda
• Expressions

• Examples from standard library

• DSL
Anton Arhipov


@antonarhipov
Developer Advocate @ JetBrains
Idiomatic kotlin
Idiomatic kotlin
Idiomatic kotlin
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
Idiomatic kotlin
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)


}
Idiomatic kotlin
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
Ad

More Related Content

What's hot (20)

단어 의미 중의성 해소, Word Sense Disambiguation(WSD)
단어 의미 중의성 해소, Word Sense Disambiguation(WSD)단어 의미 중의성 해소, Word Sense Disambiguation(WSD)
단어 의미 중의성 해소, Word Sense Disambiguation(WSD)
찬희 이
 
Java 8 Lambda Built-in Functional Interfaces
Java 8 Lambda Built-in Functional InterfacesJava 8 Lambda Built-in Functional Interfaces
Java 8 Lambda Built-in Functional Interfaces
Ganesh Samarthyam
 
25 the ratio, root, and ratio comparison test x
25 the ratio, root, and ratio  comparison test x25 the ratio, root, and ratio  comparison test x
25 the ratio, root, and ratio comparison test x
math266
 
Designing with Capabilities
Designing with CapabilitiesDesigning with Capabilities
Designing with Capabilities
Scott Wlaschin
 
Implementing the IO Monad in Scala
Implementing the IO Monad in ScalaImplementing the IO Monad in Scala
Implementing the IO Monad in Scala
Hermann Hueck
 
Ode powerpoint presentation1
Ode powerpoint presentation1Ode powerpoint presentation1
Ode powerpoint presentation1
Pokkarn Narkhede
 
Intro to functional programming
Intro to functional programmingIntro to functional programming
Intro to functional programming
Assaf Gannon
 
Domain Driven Design with the F# type System -- NDC London 2013
Domain Driven Design with the F# type System -- NDC London 2013Domain Driven Design with the F# type System -- NDC London 2013
Domain Driven Design with the F# type System -- NDC London 2013
Scott Wlaschin
 
1 kotlin vs. java: some java issues addressed in kotlin
1  kotlin vs. java: some java issues addressed in kotlin1  kotlin vs. java: some java issues addressed in kotlin
1 kotlin vs. java: some java issues addressed in kotlin
Sergey Bandysik
 
Introduction to java 8 stream api
Introduction to java 8 stream apiIntroduction to java 8 stream api
Introduction to java 8 stream api
Vladislav sidlyarevich
 
Functional Programming with Groovy
Functional Programming with GroovyFunctional Programming with Groovy
Functional Programming with Groovy
Arturo Herrero
 
Function in c program
Function in c programFunction in c program
Function in c program
umesh patil
 
Лекция 9. Поиск кратчайшего пути в графе
Лекция 9. Поиск кратчайшего пути в графеЛекция 9. Поиск кратчайшего пути в графе
Лекция 9. Поиск кратчайшего пути в графе
Mikhail Kurnosov
 
Calculus of variations
Calculus of variationsCalculus of variations
Calculus of variations
Solo Hermelin
 
Exploring ZIO Prelude: The game changer for typeclasses in Scala
Exploring ZIO Prelude: The game changer for typeclasses in ScalaExploring ZIO Prelude: The game changer for typeclasses in Scala
Exploring ZIO Prelude: The game changer for typeclasses in Scala
Jorge Vásquez
 
ZIO Queue
ZIO QueueZIO Queue
ZIO Queue
John De Goes
 
Ordinary differential equation
Ordinary differential equationOrdinary differential equation
Ordinary differential equation
DnyaneshwarPardeshi1
 
Let's make a contract: the art of designing a Java API
Let's make a contract: the art of designing a Java APILet's make a contract: the art of designing a Java API
Let's make a contract: the art of designing a Java API
Mario Fusco
 
Pipeline oriented programming
Pipeline oriented programmingPipeline oriented programming
Pipeline oriented programming
Scott Wlaschin
 
Complex function
Complex functionComplex function
Complex function
Shrey Patel
 
단어 의미 중의성 해소, Word Sense Disambiguation(WSD)
단어 의미 중의성 해소, Word Sense Disambiguation(WSD)단어 의미 중의성 해소, Word Sense Disambiguation(WSD)
단어 의미 중의성 해소, Word Sense Disambiguation(WSD)
찬희 이
 
Java 8 Lambda Built-in Functional Interfaces
Java 8 Lambda Built-in Functional InterfacesJava 8 Lambda Built-in Functional Interfaces
Java 8 Lambda Built-in Functional Interfaces
Ganesh Samarthyam
 
25 the ratio, root, and ratio comparison test x
25 the ratio, root, and ratio  comparison test x25 the ratio, root, and ratio  comparison test x
25 the ratio, root, and ratio comparison test x
math266
 
Designing with Capabilities
Designing with CapabilitiesDesigning with Capabilities
Designing with Capabilities
Scott Wlaschin
 
Implementing the IO Monad in Scala
Implementing the IO Monad in ScalaImplementing the IO Monad in Scala
Implementing the IO Monad in Scala
Hermann Hueck
 
Ode powerpoint presentation1
Ode powerpoint presentation1Ode powerpoint presentation1
Ode powerpoint presentation1
Pokkarn Narkhede
 
Intro to functional programming
Intro to functional programmingIntro to functional programming
Intro to functional programming
Assaf Gannon
 
Domain Driven Design with the F# type System -- NDC London 2013
Domain Driven Design with the F# type System -- NDC London 2013Domain Driven Design with the F# type System -- NDC London 2013
Domain Driven Design with the F# type System -- NDC London 2013
Scott Wlaschin
 
1 kotlin vs. java: some java issues addressed in kotlin
1  kotlin vs. java: some java issues addressed in kotlin1  kotlin vs. java: some java issues addressed in kotlin
1 kotlin vs. java: some java issues addressed in kotlin
Sergey Bandysik
 
Functional Programming with Groovy
Functional Programming with GroovyFunctional Programming with Groovy
Functional Programming with Groovy
Arturo Herrero
 
Function in c program
Function in c programFunction in c program
Function in c program
umesh patil
 
Лекция 9. Поиск кратчайшего пути в графе
Лекция 9. Поиск кратчайшего пути в графеЛекция 9. Поиск кратчайшего пути в графе
Лекция 9. Поиск кратчайшего пути в графе
Mikhail Kurnosov
 
Calculus of variations
Calculus of variationsCalculus of variations
Calculus of variations
Solo Hermelin
 
Exploring ZIO Prelude: The game changer for typeclasses in Scala
Exploring ZIO Prelude: The game changer for typeclasses in ScalaExploring ZIO Prelude: The game changer for typeclasses in Scala
Exploring ZIO Prelude: The game changer for typeclasses in Scala
Jorge Vásquez
 
Let's make a contract: the art of designing a Java API
Let's make a contract: the art of designing a Java APILet's make a contract: the art of designing a Java API
Let's make a contract: the art of designing a Java API
Mario Fusco
 
Pipeline oriented programming
Pipeline oriented programmingPipeline oriented programming
Pipeline oriented programming
Scott Wlaschin
 
Complex function
Complex functionComplex function
Complex function
Shrey Patel
 

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
BTI360
 
Exploring Koltin on Android
Exploring Koltin on AndroidExploring Koltin on Android
Exploring Koltin on Android
Deepanshu 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 2
Kirill 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 3
Kirill Rozov
 
Concurrent Application Development using Scala
Concurrent Application Development using ScalaConcurrent Application Development using Scala
Concurrent Application Development using Scala
Siarhiej Siemianchuk
 
Derping With Kotlin
Derping With KotlinDerping With Kotlin
Derping With Kotlin
Ross Tuck
 
Kotlinify Your Project!
Kotlinify Your Project!Kotlinify Your Project!
Kotlinify Your Project!
OrNoyman
 
SDC - Einführung in Scala
SDC - Einführung in ScalaSDC - Einführung in Scala
SDC - Einführung in Scala
Christian Baranowski
 
Introduction to Swift programming language.
Introduction to Swift programming language.Introduction to Swift programming language.
Introduction to Swift programming language.
Icalia Labs
 
Introduction to Scala
Introduction to ScalaIntroduction to Scala
Introduction to Scala
Aleksandar Prokopec
 
Parametricity - #cljsyd - May, 2015
Parametricity - #cljsyd - May, 2015Parametricity - #cljsyd - May, 2015
Parametricity - #cljsyd - May, 2015
Leonardo Borges
 
Pooya Khaloo Presentation on IWMC 2015
Pooya Khaloo Presentation on IWMC 2015Pooya Khaloo Presentation on IWMC 2015
Pooya Khaloo Presentation on IWMC 2015
Iran Entrepreneurship Association
 
A swift introduction to Swift
A swift introduction to SwiftA swift introduction to Swift
A swift introduction to Swift
Giordano Scalzo
 
Ast transformations
Ast transformationsAst transformations
Ast transformations
HamletDRC
 
Dip into Coroutines - KTUG Munich 202303
Dip into Coroutines - KTUG Munich 202303Dip into Coroutines - KTUG Munich 202303
Dip into Coroutines - KTUG Munich 202303
Alex Semin
 
Swift-Programming Part 1
Swift-Programming Part 1Swift-Programming Part 1
Swift-Programming Part 1
Mindfire Solutions
 
Why Scala is the better Java
Why Scala is the better JavaWhy Scala is the better Java
Why Scala is the better Java
Thomas Kaiser
 
Kotlin
KotlinKotlin
Kotlin
Jemo Mgebrishvili
 
ScalaBlitz
ScalaBlitzScalaBlitz
ScalaBlitz
Aleksandar Prokopec
 
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
BTI360
 
Exploring Koltin on Android
Exploring Koltin on AndroidExploring Koltin on Android
Exploring Koltin on Android
Deepanshu 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 2
Kirill 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 3
Kirill Rozov
 
Concurrent Application Development using Scala
Concurrent Application Development using ScalaConcurrent Application Development using Scala
Concurrent Application Development using Scala
Siarhiej Siemianchuk
 
Derping With Kotlin
Derping With KotlinDerping With Kotlin
Derping With Kotlin
Ross 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, 2015
Leonardo Borges
 
A swift introduction to Swift
A swift introduction to SwiftA swift introduction to Swift
A swift introduction to Swift
Giordano Scalzo
 
Ast transformations
Ast transformationsAst transformations
Ast transformations
HamletDRC
 
Dip into Coroutines - KTUG Munich 202303
Dip into Coroutines - KTUG Munich 202303Dip into Coroutines - KTUG Munich 202303
Dip into Coroutines - KTUG Munich 202303
Alex Semin
 
Why Scala is the better Java
Why Scala is the better JavaWhy Scala is the better Java
Why Scala is the better Java
Thomas Kaiser
 
Ad

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
Anton 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 TeamCity
Anton Arhipov
 
Build pipelines with TeamCity
Build pipelines with TeamCityBuild pipelines with TeamCity
Build pipelines with TeamCity
Anton 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 hour
Anton 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 hour
Anton 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 DSL
Anton Arhipov
 
Build pipelines with TeamCity
Build pipelines with TeamCityBuild pipelines with TeamCity
Build pipelines with TeamCity
Anton 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 TestContainers
Anton Arhipov
 
GeeCON Prague 2017 - TestContainers
GeeCON Prague 2017 - TestContainersGeeCON Prague 2017 - TestContainers
GeeCON Prague 2017 - TestContainers
Anton 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 reloading
Anton 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 hassle
Anton 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 reloading
Anton 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 reloading
Anton Arhipov
 
JUG.ua 20170225 - Java bytecode instrumentation
JUG.ua 20170225 - Java bytecode instrumentationJUG.ua 20170225 - Java bytecode instrumentation
JUG.ua 20170225 - Java bytecode instrumentation
Anton 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 reloading
Anton 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 hassle
Anton 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 reloading
Anton Arhipov
 
JEEConf 2017 - Having fun with Javassist
JEEConf 2017 - Having fun with JavassistJEEConf 2017 - Having fun with Javassist
JEEConf 2017 - Having fun with Javassist
Anton Arhipov
 
Devclub 01/2017 - (Не)адекватное Java-интервью
Devclub 01/2017 - (Не)адекватное Java-интервьюDevclub 01/2017 - (Не)адекватное Java-интервью
Devclub 01/2017 - (Не)адекватное Java-интервью
Anton Arhipov
 
JavaZone 2022 - Building Kotlin DSL.pdf
JavaZone 2022 - Building Kotlin DSL.pdfJavaZone 2022 - Building Kotlin DSL.pdf
JavaZone 2022 - Building Kotlin DSL.pdf
Anton 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 TeamCity
Anton Arhipov
 
Build pipelines with TeamCity
Build pipelines with TeamCityBuild pipelines with TeamCity
Build pipelines with TeamCity
Anton 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 hour
Anton 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 hour
Anton 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 DSL
Anton Arhipov
 
Build pipelines with TeamCity
Build pipelines with TeamCityBuild pipelines with TeamCity
Build pipelines with TeamCity
Anton 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 TestContainers
Anton Arhipov
 
GeeCON Prague 2017 - TestContainers
GeeCON Prague 2017 - TestContainersGeeCON Prague 2017 - TestContainers
GeeCON Prague 2017 - TestContainers
Anton 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 reloading
Anton 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 hassle
Anton 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 reloading
Anton 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 reloading
Anton Arhipov
 
JUG.ua 20170225 - Java bytecode instrumentation
JUG.ua 20170225 - Java bytecode instrumentationJUG.ua 20170225 - Java bytecode instrumentation
JUG.ua 20170225 - Java bytecode instrumentation
Anton 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 reloading
Anton 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 hassle
Anton 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 reloading
Anton Arhipov
 
JEEConf 2017 - Having fun with Javassist
JEEConf 2017 - Having fun with JavassistJEEConf 2017 - Having fun with Javassist
JEEConf 2017 - Having fun with Javassist
Anton Arhipov
 
Devclub 01/2017 - (Не)адекватное Java-интервью
Devclub 01/2017 - (Не)адекватное Java-интервьюDevclub 01/2017 - (Не)адекватное Java-интервью
Devclub 01/2017 - (Не)адекватное Java-интервью
Anton Arhipov
 
Ad

Recently uploaded (20)

Big Data Analytics Quick Research Guide by Arthur Morgan
Big Data Analytics Quick Research Guide by Arthur MorganBig Data Analytics Quick Research Guide by Arthur Morgan
Big Data Analytics Quick Research Guide by Arthur Morgan
Arthur Morgan
 
Heap, Types of Heap, Insertion and Deletion
Heap, Types of Heap, Insertion and DeletionHeap, Types of Heap, Insertion and Deletion
Heap, Types of Heap, Insertion and Deletion
Jaydeep Kale
 
AI and Data Privacy in 2025: Global Trends
AI and Data Privacy in 2025: Global TrendsAI and Data Privacy in 2025: Global Trends
AI and Data Privacy in 2025: Global Trends
InData Labs
 
Designing Low-Latency Systems with Rust and ScyllaDB: An Architectural Deep Dive
Designing Low-Latency Systems with Rust and ScyllaDB: An Architectural Deep DiveDesigning Low-Latency Systems with Rust and ScyllaDB: An Architectural Deep Dive
Designing Low-Latency Systems with Rust and ScyllaDB: An Architectural Deep Dive
ScyllaDB
 
Build Your Own Copilot & Agents For Devs
Build Your Own Copilot & Agents For DevsBuild Your Own Copilot & Agents For Devs
Build Your Own Copilot & Agents For Devs
Brian McKeiver
 
HCL Nomad Web – Best Practices und Verwaltung von Multiuser-Umgebungen
HCL Nomad Web – Best Practices und Verwaltung von Multiuser-UmgebungenHCL Nomad Web – Best Practices und Verwaltung von Multiuser-Umgebungen
HCL Nomad Web – Best Practices und Verwaltung von Multiuser-Umgebungen
panagenda
 
Cyber Awareness overview for 2025 month of security
Cyber Awareness overview for 2025 month of securityCyber Awareness overview for 2025 month of security
Cyber Awareness overview for 2025 month of security
riccardosl1
 
How analogue intelligence complements AI
How analogue intelligence complements AIHow analogue intelligence complements AI
How analogue intelligence complements AI
Paul Rowe
 
DevOpsDays Atlanta 2025 - Building 10x Development Organizations.pptx
DevOpsDays Atlanta 2025 - Building 10x Development Organizations.pptxDevOpsDays Atlanta 2025 - Building 10x Development Organizations.pptx
DevOpsDays Atlanta 2025 - Building 10x Development Organizations.pptx
Justin Reock
 
Linux Support for SMARC: How Toradex Empowers Embedded Developers
Linux Support for SMARC: How Toradex Empowers Embedded DevelopersLinux Support for SMARC: How Toradex Empowers Embedded Developers
Linux Support for SMARC: How Toradex Empowers Embedded Developers
Toradex
 
Electronic_Mail_Attacks-1-35.pdf by xploit
Electronic_Mail_Attacks-1-35.pdf by xploitElectronic_Mail_Attacks-1-35.pdf by xploit
Electronic_Mail_Attacks-1-35.pdf by xploit
niftliyevhuseyn
 
Noah Loul Shares 5 Steps to Implement AI Agents for Maximum Business Efficien...
Noah Loul Shares 5 Steps to Implement AI Agents for Maximum Business Efficien...Noah Loul Shares 5 Steps to Implement AI Agents for Maximum Business Efficien...
Noah Loul Shares 5 Steps to Implement AI Agents for Maximum Business Efficien...
Noah Loul
 
Andrew Marnell: Transforming Business Strategy Through Data-Driven Insights
Andrew Marnell: Transforming Business Strategy Through Data-Driven InsightsAndrew Marnell: Transforming Business Strategy Through Data-Driven Insights
Andrew Marnell: Transforming Business Strategy Through Data-Driven Insights
Andrew Marnell
 
Enhancing ICU Intelligence: How Our Functional Testing Enabled a Healthcare I...
Enhancing ICU Intelligence: How Our Functional Testing Enabled a Healthcare I...Enhancing ICU Intelligence: How Our Functional Testing Enabled a Healthcare I...
Enhancing ICU Intelligence: How Our Functional Testing Enabled a Healthcare I...
Impelsys Inc.
 
IEDM 2024 Tutorial2_Advances in CMOS Technologies and Future Directions for C...
IEDM 2024 Tutorial2_Advances in CMOS Technologies and Future Directions for C...IEDM 2024 Tutorial2_Advances in CMOS Technologies and Future Directions for C...
IEDM 2024 Tutorial2_Advances in CMOS Technologies and Future Directions for C...
organizerofv
 
TrustArc Webinar: Consumer Expectations vs Corporate Realities on Data Broker...
TrustArc Webinar: Consumer Expectations vs Corporate Realities on Data Broker...TrustArc Webinar: Consumer Expectations vs Corporate Realities on Data Broker...
TrustArc Webinar: Consumer Expectations vs Corporate Realities on Data Broker...
TrustArc
 
Role of Data Annotation Services in AI-Powered Manufacturing
Role of Data Annotation Services in AI-Powered ManufacturingRole of Data Annotation Services in AI-Powered Manufacturing
Role of Data Annotation Services in AI-Powered Manufacturing
Andrew Leo
 
Transcript: #StandardsGoals for 2025: Standards & certification roundup - Tec...
Transcript: #StandardsGoals for 2025: Standards & certification roundup - Tec...Transcript: #StandardsGoals for 2025: Standards & certification roundup - Tec...
Transcript: #StandardsGoals for 2025: Standards & certification roundup - Tec...
BookNet Canada
 
Increasing Retail Store Efficiency How can Planograms Save Time and Money.pptx
Increasing Retail Store Efficiency How can Planograms Save Time and Money.pptxIncreasing Retail Store Efficiency How can Planograms Save Time and Money.pptx
Increasing Retail Store Efficiency How can Planograms Save Time and Money.pptx
Anoop Ashok
 
Generative Artificial Intelligence (GenAI) in Business
Generative Artificial Intelligence (GenAI) in BusinessGenerative Artificial Intelligence (GenAI) in Business
Generative Artificial Intelligence (GenAI) in Business
Dr. Tathagat Varma
 
Big Data Analytics Quick Research Guide by Arthur Morgan
Big Data Analytics Quick Research Guide by Arthur MorganBig Data Analytics Quick Research Guide by Arthur Morgan
Big Data Analytics Quick Research Guide by Arthur Morgan
Arthur Morgan
 
Heap, Types of Heap, Insertion and Deletion
Heap, Types of Heap, Insertion and DeletionHeap, Types of Heap, Insertion and Deletion
Heap, Types of Heap, Insertion and Deletion
Jaydeep Kale
 
AI and Data Privacy in 2025: Global Trends
AI and Data Privacy in 2025: Global TrendsAI and Data Privacy in 2025: Global Trends
AI and Data Privacy in 2025: Global Trends
InData Labs
 
Designing Low-Latency Systems with Rust and ScyllaDB: An Architectural Deep Dive
Designing Low-Latency Systems with Rust and ScyllaDB: An Architectural Deep DiveDesigning Low-Latency Systems with Rust and ScyllaDB: An Architectural Deep Dive
Designing Low-Latency Systems with Rust and ScyllaDB: An Architectural Deep Dive
ScyllaDB
 
Build Your Own Copilot & Agents For Devs
Build Your Own Copilot & Agents For DevsBuild Your Own Copilot & Agents For Devs
Build Your Own Copilot & Agents For Devs
Brian McKeiver
 
HCL Nomad Web – Best Practices und Verwaltung von Multiuser-Umgebungen
HCL Nomad Web – Best Practices und Verwaltung von Multiuser-UmgebungenHCL Nomad Web – Best Practices und Verwaltung von Multiuser-Umgebungen
HCL Nomad Web – Best Practices und Verwaltung von Multiuser-Umgebungen
panagenda
 
Cyber Awareness overview for 2025 month of security
Cyber Awareness overview for 2025 month of securityCyber Awareness overview for 2025 month of security
Cyber Awareness overview for 2025 month of security
riccardosl1
 
How analogue intelligence complements AI
How analogue intelligence complements AIHow analogue intelligence complements AI
How analogue intelligence complements AI
Paul Rowe
 
DevOpsDays Atlanta 2025 - Building 10x Development Organizations.pptx
DevOpsDays Atlanta 2025 - Building 10x Development Organizations.pptxDevOpsDays Atlanta 2025 - Building 10x Development Organizations.pptx
DevOpsDays Atlanta 2025 - Building 10x Development Organizations.pptx
Justin Reock
 
Linux Support for SMARC: How Toradex Empowers Embedded Developers
Linux Support for SMARC: How Toradex Empowers Embedded DevelopersLinux Support for SMARC: How Toradex Empowers Embedded Developers
Linux Support for SMARC: How Toradex Empowers Embedded Developers
Toradex
 
Electronic_Mail_Attacks-1-35.pdf by xploit
Electronic_Mail_Attacks-1-35.pdf by xploitElectronic_Mail_Attacks-1-35.pdf by xploit
Electronic_Mail_Attacks-1-35.pdf by xploit
niftliyevhuseyn
 
Noah Loul Shares 5 Steps to Implement AI Agents for Maximum Business Efficien...
Noah Loul Shares 5 Steps to Implement AI Agents for Maximum Business Efficien...Noah Loul Shares 5 Steps to Implement AI Agents for Maximum Business Efficien...
Noah Loul Shares 5 Steps to Implement AI Agents for Maximum Business Efficien...
Noah Loul
 
Andrew Marnell: Transforming Business Strategy Through Data-Driven Insights
Andrew Marnell: Transforming Business Strategy Through Data-Driven InsightsAndrew Marnell: Transforming Business Strategy Through Data-Driven Insights
Andrew Marnell: Transforming Business Strategy Through Data-Driven Insights
Andrew Marnell
 
Enhancing ICU Intelligence: How Our Functional Testing Enabled a Healthcare I...
Enhancing ICU Intelligence: How Our Functional Testing Enabled a Healthcare I...Enhancing ICU Intelligence: How Our Functional Testing Enabled a Healthcare I...
Enhancing ICU Intelligence: How Our Functional Testing Enabled a Healthcare I...
Impelsys Inc.
 
IEDM 2024 Tutorial2_Advances in CMOS Technologies and Future Directions for C...
IEDM 2024 Tutorial2_Advances in CMOS Technologies and Future Directions for C...IEDM 2024 Tutorial2_Advances in CMOS Technologies and Future Directions for C...
IEDM 2024 Tutorial2_Advances in CMOS Technologies and Future Directions for C...
organizerofv
 
TrustArc Webinar: Consumer Expectations vs Corporate Realities on Data Broker...
TrustArc Webinar: Consumer Expectations vs Corporate Realities on Data Broker...TrustArc Webinar: Consumer Expectations vs Corporate Realities on Data Broker...
TrustArc Webinar: Consumer Expectations vs Corporate Realities on Data Broker...
TrustArc
 
Role of Data Annotation Services in AI-Powered Manufacturing
Role of Data Annotation Services in AI-Powered ManufacturingRole of Data Annotation Services in AI-Powered Manufacturing
Role of Data Annotation Services in AI-Powered Manufacturing
Andrew Leo
 
Transcript: #StandardsGoals for 2025: Standards & certification roundup - Tec...
Transcript: #StandardsGoals for 2025: Standards & certification roundup - Tec...Transcript: #StandardsGoals for 2025: Standards & certification roundup - Tec...
Transcript: #StandardsGoals for 2025: Standards & certification roundup - Tec...
BookNet Canada
 
Increasing Retail Store Efficiency How can Planograms Save Time and Money.pptx
Increasing Retail Store Efficiency How can Planograms Save Time and Money.pptxIncreasing Retail Store Efficiency How can Planograms Save Time and Money.pptx
Increasing Retail Store Efficiency How can Planograms Save Time and Money.pptx
Anoop Ashok
 
Generative Artificial Intelligence (GenAI) in Business
Generative Artificial Intelligence (GenAI) in BusinessGenerative Artificial Intelligence (GenAI) in Business
Generative Artificial Intelligence (GenAI) in Business
Dr. Tathagat Varma
 

Idiomatic kotlin

  • 2. Agenda • Expressions • Examples from standard library • DSL
  • 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
  • 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) }
  • 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")