Kotlin

Why should I Care?







Created by Tomasz Kucharzyk

What is Kotlin?

Not only ketchup

  • JVM language like Scala or Groovy
  • Created by Jetbrains in 2010
  • Open sourced under Apache licence
  • Version 1.0 released in February 2016

SHORT JVM LANGUAGES HISTORY

1991

Java project initiated

1995

Java 1.0 released

2003

Groovy 1.0 released

2004

Scala 1.0 released

2010

Kotlin project initiated

  • For internal Jetbrains usage
  • Developed in Saint Petersburg
  • 30km from Kotlin island

Kotlin project goals

  • industrial-strength object-oriented language
  • "better language" than Java
  • fully interoperable with Java code
  • allow gradual migration from Java to Kotlin
  • compile as quickly as Java

2011

Public Kotlin announcement

2012

JetBrains open sourced Kotlin

2016

Kotlin 1.0 released

2017

Kotlin 1.1 released

  • Java 8 support
  • Gradle script kotlin
  • Coroutines

2017

Kotlin 1.2 released

  • Sharing code between JVM and JavaScript

2023

Kotlin 1.9 released

  • Java 21 support
  • Kotlin Multiplatform is stable and production-ready
  • Server
  • Android
  • iOS
  • Desktop
  • Web

Google trends

What happened?

Google announces official Kotlin support for Android

Who really cares?

  • Jetbrains in their products
  • Gradle (GRADLE SCRIPT KOTLIN)
  • Broadcom (KOTLIN IN SPRING)
  • Google (PRIMARY ANDROID LANGUAGE)
  • Corda (open-source ledger banking platform)
  • Atlassian
  • Coursera
  • Allegro Group
  • Many other companies

Why Kotlin?

  • INTEROPERABLE WITH JAVA
  • PRAGMATIC
  • EXTENDABLE
  • SAFE
  • FUN

REQUIREMENTS

  • JAVA 6 OR HIGHER
  • MAVEN OR GRADLE PLUGIN
  • OR STANDALONE COMPILER
  • THAT'S ALL

IDE SUPPORT

  • YOU NEED INTELLIJ IDEA
  • OR ECLIPSE WITH OFFICIAL PLUGIN
  • OR NETBEANS WITH OFFICIAL PLUGIN
  • OR EVEN VIM OR EMACS :)

"Talk is cheap

Show me the code"

Linus Tornvalds

Hello World

Java


public class HelloWorld {
    public static void main(String[] args) {
        System.out.println("Hello World");
    }
}

Kotlin


fun main(args: Array<String>) {
    println("Hello World")
}

  • Function as first class citizen
  • No primitive types
  • No statics
  • Optional semicolons

Kotlin Types

  • int -> Int
  • double -> Double
  • byte[] -> Array<Byte>
  • void -> Unit
  • Object -> Any

VARIABLES

VARIABLES


    public void variables() {  // JAVA
        Double numer;
        final Double PI = Math.PI;
        String text = "Hello";
        BigDecimal decimal0 = new BigDecimal("0");
        BigDecimal decimal1 = new BigDecimal("1");
        BigDecimal decimal2 = null;
    }

    fun variables() { // KOTLIN
        var numer: Double
        val PI = Math.PI
        var text = "Hello"
        var decimal0: BigDecimal = BigDecimal("0")
        var decimal1 = BigDecimal("1")
        var decimal2: BigDecimal = null // COMPILE ERROR!!!
    }

VARIABLES


    public void variables() { // JAVA
        Double numer;
        final Double PI = Math.PI;
        String text = "Hello";
        BigDecimal decimal0 = new BigDecimal("0");
        BigDecimal decimal1 = new BigDecimal("1");
        BigDecimal decimal2 = null;
    }

    fun variables() { // KOTLIN
        var numer: Double
        val PI = Math.PI
        var text = "Hello"
        var decimal0: BigDecimal = BigDecimal("0")
        var decimal1 = BigDecimal("1")
        var decimal2: BigDecimal? = null // NULLABLE TYPE
    }

REFACTORING TO KOTLIN

ON SIMPLE EXAMPLE

FIBONNACCI NUMBERS

0, 1, 1, 2, 3, 5, 8, 13, 24, 34, 55, 89, 144...

FIBONACCI #0


    public Integer fib(Integer x) throws Exception {
        if (x.equals(0)) {
            return 0;
        } else if (x.equals(1)) {
            return 1;
        } else if (x >= 2 && x <= 64) {
            return fib(x - 1) + fib(x - 2);
        } else {
            throw new Exception("Number " + x + " is out of range 0..64");
        }
    }

FIBONACCI #1

JAVA LIKE VERSION


    fun fib(x: Int): Int {
        if (x.equals(0)) {
            return 0
        } else if (x.equals(1)) {
            return 1
        } else if (x >= 2 && x <= 64) {
            return fib(x - 1) + fib(x - 2)
        } else {
            throw Exception("Number " + x + " is out of range 0..64")
        }
    }

FIBONACCI #2

== OPERATOR


    fun fib(x: Int): Int {
        if (x == 0) {
            return 0
        } else if (x == 1) {
            return 1
        } else if (x >= 2 && x <= 64) {
            return fib(x - 1) + fib(x - 2)
        } else {
            throw Exception("Number " + x + " is out of range 0..64")
        }
    }

FIBONACCI #3

RANGE OPERATOR


    fun fib(x: Int): Int {
        if (x == 0) {
            return 0
        } else if (x == 1) {
            return 1
        } else if (x in 2..64) {
            return fib(x - 1) + fib(x - 2)
        } else {
            throw Exception("Number " + x + " is out of range 0..64")
        }
    }

FIBONACCI #4

STRING TEMPLATES


    fun fib(x: Int): Int {
        if (x == 0) {
            return 0
        } else if (x == 1) {
            return 1
        } else if (x in 2..64) {
            return fib(x - 1) + fib(x - 2)
        } else {
            throw Exception("Number $x is out of range 0..64")
        }
    }

FIBONACCI #5

WHEN EXPRESSION


    fun fib(x: Int): Int {
        when {
            x == 0 -> return 0
            x == 1 -> return 1
            x in 2..64 -> return fib(x - 1) + fib(x - 2)
            else -> throw Exception("Number $x is out of range 0..64")
        }
    }

FIBONACCI #6

WHEN WITH ARGUMENT


    fun fib(x: Int): Int {
        when (x) {
            0 -> return 0
            1 -> return 1
            in 2..64 -> return fib(x - 1) + fib(x - 2)
            else -> throw Exception("Number $x is out of range 0..64")
        }
    }

FIBONACCI #6

EXPRESSION AS FUNCTION


  fun fib(x: Int): Int = when (x) {
        0 -> 0
        1 -> 1
        in 2..64 -> fib(x - 1) + fib(x - 2)
        else -> throw Exception("Number $x is out of range 0..64")
    }

  fun fib(x: Int): Int = when (x) {
        0 -> 0
        1 -> 1
        in 2..64 -> fib(x - 1) + fib(x - 2)
        else -> throw Exception("Number $x is out of range 0..64")
    }

FUNCTIONS

EXPRESSION AS FUNCTION


fun divide(a: Double, b: Double): Double = a / b

INFERRED TYPE


fun divide(a: Double, b: Double) = a / b

NAMED PARAMETERS


    fun divide(a: Double, b: Double) = a / b

    val x = divide(7.5, 4.0)
    val y = divide(b = 4.0, a = 7.5)

OPTIONAL PARAMETERS


    fun function(x: Int = 0, y: Int = 5, z: Int = 0) = 2 * x + y - z

    fun functionTest() {
        val a = function(1, 2, 3)
        val b = function(1, 2)
        val c = function(1)
        val d = function(z = 3, y = 2, x = 1)
        val e = function(z = 3, y = 2)
        val f = function(2, z = 3)
    }

NULL SAFETY

NULLABLE TYPES


fun function(x: Int = 0, y: Int = 5, z: Int = 0) = 2 * x + y - z

fun functionTest() {
    val a = function(1, null, 3) // Doesn't compile!!!
}

NULLABLE TYPES


fun function(x: Int = 0, y: Int? = 5, z: Int = 0) = 2 * x + y - z
// Doesn't compile!!!

fun functionTest() {
    val a = function(1, null, 3)
}

NULLABLE TYPES


fun function(x: Int = 0, y: Int? = 5, z: Int = 0): Int {
    if (y != null) {
        return 2 * x + y - z
    } else {
        return 0
    }
}

fun functionTest() {
    val a = function(1, null, 3)
}

NULLABLE TYPES


fun function(x: Int = 0, y: Int? = 5, z: Int = 0): Int {
    return if (y != null) 2 * x + y - z else 0
}

fun functionTest() {
    val a = function(1, null, 3)
}

NULLABLE TYPES


class Driver(val name: String, val surname: String)

class Car(val driver: Driver?)

class Garage(var car: Car?)

fun garageTest() {
    var driver = Driver("John","Doe")
    var car = Car(driver)
    var garage = Garage(car)

    //println(garage.car.driver.name) // Doesn't compile
    println(garage.car?.driver?.name) // May print null
    println(garage.car?.driver?.name?:"Unknown") // or Unknown
}

CLASSES

CLASSES

  • PUBLIC BY DEFAULT
  • NO PACKAGE SCOPE
  • FINAL BY DEFAULT
  • FILENAME DOESN'T MATTER
  • MANY PUBLIC CLASSES IN ONE FILE
  • GETTERS BY DEFAULT (ON JAVA SIDE)

SIMPLEST CLASS


class EmptyClass

SAMPLE CLASS


class Driver {
    val name: String
    val surname: String
    var age: Int
    var eyeColor: String
    var married = false
    var birthDate: Date? = null

    constructor(name: String,
                surname: String,
                age: Int,
                eyeColor: String = "black") {
        this.name = name
        this.surname = surname
        this.age = age
        this.eyeColor = eyeColor
    }

    fun sayHello() = "Hello. I'm $name $surname. I'm $age years old."
}

PRIMARY CONSTRUCTOR


class Driver(
    val name: String,
    val surname:String,
    var age: Int,
    var eyeColor:String = "black"
){
    var married = false
    var birthDate: Date? = null

    fun sayHello() = "Hello. I'm $name $surname. I'm $age years old."
}

GETERS AND SETERS


class Basket {
    var apples = 0
    var oranges = 0
    var fruits: Int
        get() {
            return apples + oranges
        }
        set(value) {
            apples = value
            oranges = value
        }
}

fun main(args: Array<String>) {
    val basket = Basket()
    basket.apples = 1
    basket.oranges = 2
    println(basket.fruits) // 3
    basket.fruits = 5
    println(basket.fruits) //10
}

CLASS USAGE


class Driver(
    val name: String,
    val surname:String,
    var age: Int,
    var eyeColor:String = "black"
){
    var married = false
    var birthDate: Date? = null

    fun sayHello() = "Hello. I'm $name $surname. I'm $age years old."
}

fun main(args: Array<String>) {
    val driver1 = Driver("John", "Doe", 27)
    val driver2 = Driver("John", "Doe", eyeColor = "green", age = 30)
    val driver3 = Driver("John", "Doe", 30, "green")

    println(driver2 == driver3) //Equals false
}

EQUALS


    override fun equals(other: Any?): Boolean {
        if (this === other) return true
        if (other?.javaClass != javaClass) return false

        other as Driver

        if (name != other.name) return false
        if (surname != other.surname) return false
        if (age != other.age) return false
        if (eyeColor != other.eyeColor) return false
        if (married != other.married) return false
        if (birthDate != other.birthDate) return false

        return true
    }

HASHCODE


    override fun hashCode(): Int {
        var result = name.hashCode()
        result = 31 * result + surname.hashCode()
        result = 31 * result + age
        result = 31 * result + eyeColor.hashCode()
        result = 31 * result + married.hashCode()
        result = 31 * result + (birthDate?.hashCode() ?: 0)
        return result
    }

DATA CLASS


data class Driver(
        val name: String,
        val surname: String,
        var age: Int,
        var eyeColor: String = "black"
) {
    var married = false
    var birthDate: Date? = null

    fun sayHello() = "Hello. I'm $name $surname. I'm $age years old."
}


fun main(args: Array<String>) {
    val driver1 = Driver("John", "Doe", 27)
    val driver2 = Driver("John", "Doe", eyeColor = "green", age = 30)
    val driver3 = Driver("John", "Doe", 30, "green")

    println(driver2 == driver3) //Equals true!
}

DATA CLASS


data class Point(val x: Double, val y: Double)

fun main(args: Array<String>) {
    val p1 = Point(1.0, 2.0)
    val p2 = p1.copy(y = 3.0)

    val (x, y) = p2
    assert(x == 1.0)
    assert(y == 3.0)
}

DATA CLASS

  • PROVIDE EQUALS
  • PROVIDE HASHCODE
  • PROVIDE TOSTRING
  • PROVIDE COPY METHOD
  • ALLOW DESTRUCTURING
  • cannot be abstract, open, sealed or inner
  • (before 1.1) may only implement interfaces

INHERITANCE


interface Person {
    fun sayHello(): String
}

abstract class PersonWithAge(var age: Int) : Person

open class Driver(
    age: Int,
    val name: String,
    val surname: String,
    var eyeColor: String = "black"
) : PersonWithAge(age), Serializable {
    var married = false
    var birthDate: Date? = null

    override fun sayHello() = "Hello. I'm $name $surname. I'm $age years old."
}

OBJECT


object Version {
    val major = 1
    val minor = 7
    val build = 123

    fun printVersion() {
        println("v$major.$minor.$build")
    }
}

fun main(args: Array<String>) {
    Version.printVersion()
}

COMPANION OBJECT


class SimpleClass {

    fun simpleMethod() {
        print(major)
        printVersion()
    }

    companion object {
        val major = 1
        val minor = 7
        val build = 123

        fun printVersion() {
            println("v$major.$minor.$build")
        }
    }
}

SEALED CLASS


sealed class Message(val text: String) {
    class SuccessMessage(text: String) : Message(text)
    class WarningMessage(text: String, val details: String) : Message(text)
    class ErrorMessage(text: String, val errorCode: Int) : Message(text)
}

fun main(args: Array<String>) {
    val message = Message.ErrorMessage("Not Found", 404)
}

COLLECTIONS

MUTABILITY


    val immutableList = listOf(1, 2, 3)
    val immutableSet = setOf(1, 2, 3)
    val immutableMap = mapOf(Pair("a", 1), Pair("b", 1))

    val list = mutableListOf(1, 2, 3)
    val set = mutableSetOf(1, 2, 3)
    val map = mutableMapOf(Pair("a", 1), Pair("b", 1))

CLASSIC COLLECTIONS


    val list = arrayListOf(1, 2, 3)
    val set = hashSetOf(1, 2, 3)
    val map = hashMapOf(Pair("a", 1), Pair("b", 1))

ACCESS COLLECTIONS


    val list = mutableListOf(1, 2, 3, 4, 5)

    list.set(0, 7)

    list[0] = 7

JAVA 8 STREAMS


fun javaStream(employes: ArrayList<Employee>) {
    employes.stream()
            .filter({ e -> e!=null })
            .filter({ e -> e.salary>BigDecimal(3000)})
            .filter({ it.salary> BigDecimal(5000) })
            .sorted({ o1, o2 -> o2.salary.compareTo(o1.salary)})
            .map({"${it.name} gets ${it.salary} USD"})
            .forEach({ println(it)})
}

KOTLIN "STREAMS"


fun kotlinStream(employes: ArrayList<Employee>) {
    employes
            .filterNotNull()
            .filter { employee -> employee.salary > BigDecimal(3000) }
            .filter { it.salary > BigDecimal(5000) }
            .sortedByDescending { it.salary }
            .map { "${it.name} gets ${it.salary} USD" }
            .forEach { println(it) }
}

GROUPING


fun kotlinGroup(employes: ArrayList<Employee>) {
    val map: Map<BigDecimal, List<Employee>>= employes.groupBy { it.salary }
}

THERE IS A LOT MORE...

FEATURES

EXTENSIONS


fun LocalDateTime.toDate(): Date {
    return Date
            .from(this.atZone(ZoneId.systemDefault()).toInstant())
}

fun Date.toLocalDateTime(): LocalDateTime {
    return LocalDateTime
            .ofInstant(this.toInstant(), ZoneId.systemDefault())
}

fun main(args: Array<String>) {
    val date = Date()
    val localDateTime = date.toLocalDateTime()

    print(date == localDateTime.toDate()) // true
}

EXTENSIONS


fun String.toPokemonCase(): String {
    val sb = StringBuilder()
    for (i in 0..this.length - 1) {
        when {
            (i % 2 == 0) -> sb.append(this[i].toUpperCase())
            else -> sb.append(this[i].toLowerCase())
        }
    }
    return sb.toString()
}

fun main(args: Array<String>) {
    println("hello kotlin".toPokemonCase()) // HeLlO KoTlIn
}

CONDITIONAL EXPRESSIONS


fun max(a: Int, b: Int) = if (a > b) a else b

Smart Cast


interface Creature {
    fun name(): String
}
class Cat : Creature {
    override fun name() = "Cat"
    fun meow() = print("Meow")
}
class Bird : Creature {
    override fun name() = "Bird"
    fun fly() = print("I'm flying")
}


fun smartCast(creature: Creature) {
    print(creature.name())
    if (creature is Cat) {
        creature.meow()
    } else if (creature is Bird) {
        creature.fly()
    }
}

For Loop


fun collectionLoop(list: List<String>) {
    for (s in list) {
        print(s.toUpperCase())
    }
}

Range loop


fun rangeLoop() {
    for (i in 1..19) println(i)
    for (i in 1..19 step 3) println(i)
}

Range testing


fun rangeTest() {
    val a = 3.14

    if (a in 3.0..3.2) print("between 3.0 and 3.2")
}

IN OPERATOR


fun inCollectionTest(){
    val list = arrayListOf("aaa","bbb","ccc")

    if ("aaa" in list)
        println("Yes: list contains aaa")

    if ("ddd" in list)
        println("Yes: list contains ddd")
    else
        println("No: list doesn't contains ddd")
}

WHEN EXPRESSION


fun main(args: Array<String>) {
    cases("Hello")
    cases(1)
    cases(System.currentTimeMillis())
    cases(BigDecimal.ZERO)
    cases("hello")
}

fun cases(obj: Any) {
    when (obj) {
        1 -> println("One")
        "Hello" -> println("Greeting")
        is Long -> println("Long")
        !is String -> println("Not a string")
        else -> println("Unknown")
    }
}

WITH EXPRESSION


data class Person(var name:String,var surname:String, var age: Int){
    fun sayHello() = println("Hi, I'm $name $surname")
}

fun main(args: Array<String>) {
    val person = Person("john","doe",42)
    with(person){
        sayHello()
        name = name.capitalize()
        surname = surname.capitalize()
        age = if (age < 0) 0 else age
        sayHello()
    }
}

LET EXPRESSION


fun letExpression(person: Person?){

    person?.let {
        it.sayHello()
    }

}

APPLY EXPRESSION


class Point3D {
    var x=0; var y=0; var z=0;
    override fun toString() = "[$x,$y,$z]"
}

fun applyExpression() {
   val p1 = Point3D().apply { x=2; y=4; z=3 }
   val p2 = Point3D().apply { x=2; y=4; z=3 }
}

IT'S JUST KOTLIN



public inline fun <T, R> with(receiver: T, block: T.() -> R): R = receiver.block()

public inline fun <T, R> T.let(block: (T) -> R): R = block(this)

public inline fun <T> T.apply(block: T.() -> Unit): T { block(); return this }

MAP DESTRUCTURING


fun mapDestructuring() {
    val map = hashMapOf<String, Int>()
    map.put("one", 1)
    map.put("two", 2)

    for ((key, value) in map) {
        println("key = $key, value = $value")
    }
}

ONELINE MAP CREATION


fun mapOf() {

    val map = mapOf("one" to 1, "two" to 2)

    for ((key, value) in map) {
        println("key = $key, value = $value")
    }
}

ENHANCED DEPRECATED AND TODO


class TestClass {

    @Deprecated("This function is deprecated",
            ReplaceWith("newMethod()"),
            DeprecationLevel.ERROR)
    fun oldMethod() {
        TODO("OLD METHOD")
    }

    fun newMethod() {
        TODO("NEW METHOD")
    }
}

LAZY VERIABLES


class Calculator {
    val sumFrom1To100: Int by lazy {
        println("counting...")
        val sum = (1..100).sum()
        sum
    }
}

fun main(args: Array<String>) {
    val calc = Calculator()
    println("sum is ${calc.sumFrom1To100}")
    println("sum is ${calc.sumFrom1To100}")
    println("sum is ${calc.sumFrom1To100}")
}

INFIX FUNCTIONS


data class Point(val x: Int, val y: Int) {
    infix fun plus(p2: Point): Point {
        return Point(this.x + p2.x, this.y + p2.y)
    }

    infix fun minus(p2: Point): Point {
        return Point(this.x - p2.x, this.y - p2.y)
    }
}

fun main(args: Array<String>) {
    val p1 = Point(2, 5)
    val p2 = Point(7, 2)
    println(p1) // Point(x=2, y=5)
    println(p2) // Point(x=7, y=2)
    println(p1 plus p2) // Point(x=9, y=7)
    println(p1 minus p2) // Point(x=-5, y=3)
}

OPERATORS


data class Point(val x: Int, val y: Int) {
    operator fun plus(p2: Point): Point {
        return Point(this.x + p2.x, this.y + p2.y)
    }

    operator fun minus(p2: Point): Point {
        return Point(this.x - p2.x, this.y - p2.y)
    }
}

fun main(args: Array<String>) {
    val p1 = Point(2, 5)
    val p2 = Point(7, 2)
    println(p1) // Point(x=2, y=5)
    println(p2) // Point(x=7, y=2)
    println(p1 + p2) // Point(x=9, y=7)
    println(p1 - p2) // Point(x=-5, y=3)
}

MULTILINE STRING


val html = """<html>
<head></head>
<body style="background-color: black">

<h1>Hello Kotlin</h1>
<h2>Path is c:\x\y\z.txt</h2>
<pre>
SELECT column_name(s)
FROM table1
INNER JOIN table2 ON table1.column_name = table2.column_name;
</pre>

</body>
</html>
"""

LAMBDAS


fun doTheMagic(a: Int, b: Int, function: (Int, Int) -> Int): Int {
    print("apply oparation on $a and $b")
    return function(a, b)
}

fun lambdaTest() {
    val five = doTheMagic(3, 2, { x, y -> x + y })
    val ten = doTheMagic(5, 2, { x, y -> x * y })

    val division = { x: Int, y: Int -> x / y }
    val two = doTheMagic(10, 2, division)

    val alsoTwo = division(10, 2)
}

LAMBDAS


fun doTheMagic(a: Int, b: Int, function: (Int, Int) -> Int): Int {
    print("apply oparation on $a and $b")
    return function(a, b)
}

fun lambdaTest() {
    val five = doTheMagic(3, 2) {
        x, y -> x + y
    }
    val ten = doTheMagic(5, 2) {
        x, y -> x * y
    }
    val division = { x: Int, y: Int -> x / y }
    val two = doTheMagic(10, 2, division)

    val alsoTwo = division(10, 2)
}

LAMBDAS BYTECODE


  public final static lambdaTest()V
   L0
    LINENUMBER 8 L0
    ICONST_3
    ICONST_2
    GETSTATIC pl/jug/ex010/LambdasKt$lambdaTest$five$1.INSTANCE : Lpl/jug/ex010/LambdasKt$lambdaTest$five$1;
    CHECKCAST kotlin/jvm/functions/Function2
    INVOKESTATIC pl/jug/ex010/LambdasKt.doTheMagic (IILkotlin/jvm/functions/Function2;)I
    ISTORE 0
   L1
    LINENUMBER 11 L1
    RETURN
   L2
    LOCALVARIABLE five I L1 L2 0
    MAXSTACK = 3
    MAXLOCALS = 1

LAMBDAS BYTECODE


  public final static doTheMagic(IILkotlin/jvm/functions/Function2;)I
    @Lorg/jetbrains/annotations/NotNull;() // invisible, parameter 2
   L0
    LINENUMBER 4 L0
    ALOAD 2
    ILOAD 0
    INVOKESTATIC java/lang/Integer.valueOf (I)Ljava/lang/Integer;
    ILOAD 1
    INVOKESTATIC java/lang/Integer.valueOf (I)Ljava/lang/Integer;
    INVOKEINTERFACE kotlin/jvm/functions/Function2.invoke (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
    CHECKCAST java/lang/Number
    INVOKEVIRTUAL java/lang/Number.intValue ()I
    IRETURN
   L1
    LOCALVARIABLE a I L0 L1 0
    LOCALVARIABLE b I L0 L1 1
    LOCALVARIABLE function Lkotlin/jvm/functions/Function2; L0 L1 2
    MAXSTACK = 3
    MAXLOCALS = 3

INLINE FUNCTION


inline fun doTheMagic(a: Int, b: Int, function: (Int, Int) -> Int): Int {
    return function(a, b)
}

fun lambdaTest() {
    val five = doTheMagic(3, 2) {
        x, y -> x + y
    }
}

INLINE BYTECODE


  public final lambdaTest()V
   L0
    LINENUMBER 9 L0
    ALOAD 0
    ASTORE 2
    ICONST_3
    ISTORE 3
    ICONST_2
    ISTORE 4
    NOP
   L1
    LINENUMBER 15 L1
    ILOAD 3
    INVOKESTATIC java/lang/Integer.valueOf (I)Ljava/lang/Integer;
    ILOAD 4
    INVOKESTATIC java/lang/Integer.valueOf (I)Ljava/lang/Integer;
    CHECKCAST java/lang/Number
    INVOKEVIRTUAL java/lang/Number.intValue ()I
    ISTORE 5
    CHECKCAST java/lang/Number
    INVOKEVIRTUAL java/lang/Number.intValue ()I
    ISTORE 6
   L2
    LINENUMBER 11 L2
    ILOAD 6
    ILOAD 5
    IADD
   L3
    GOTO L4
   L4
    INVOKESTATIC java/lang/Integer.valueOf (I)Ljava/lang/Integer;
    CHECKCAST java/lang/Number
    INVOKEVIRTUAL java/lang/Number.intValue ()I
    GOTO L5
   L5
   L6
    LINENUMBER 9 L6
    ISTORE 1
   L7
    LINENUMBER 13 L7
    RETURN
   L8
    LOCALVARIABLE x I L2 L4 6
    LOCALVARIABLE y I L2 L4 5
    LOCALVARIABLE $i$a$1$doTheMagic I L2 L4 7
    LOCALVARIABLE this_$iv Lpl/jug/ex010/Lambdas; L1 L5 2
    LOCALVARIABLE a$iv I L1 L5 3
    LOCALVARIABLE b$iv I L1 L5 4
    LOCALVARIABLE $i$f$doTheMagic I L1 L5 8
    LOCALVARIABLE five I L7 L8 1
    LOCALVARIABLE this Lpl/jug/ex010/Lambdas; L0 L8 0
    MAXSTACK = 2
    MAXLOCALS = 9

There is a lot more!

KOTLIN FUTURE

  • Kotlin Multiplatform
  • Reactive applications
  • KOTLIN NATIVE
  • WASM

CONCLUSIONS

GOOD PARTS

  • POWERFULL
  • EASY LEARNING CURVE
  • CTRL+ALT+SHIFT+K
  • JAVA INTEROPERABILITY
  • TYPE SAFETY
  • MORE FUN

BAD PARTS

  • NONE

BAD PARTS

  • NEW SYNTAX
  • COMPILATION OVERHEAD
  • CHECKED EXCEPTIONS?
  • NO PACKAGE SCOPE
  • MINOR INCOMPATIBILITIES WITH LIBRARIES
  • IT'S SOMETIMES CONFUSED

QUESTIONS?

THANK YOU