Topics About me A tiny introduction to Kotlin Function types Extension points Function composition, currying and partial application funKTionale’s Option, Either and Disjunction Future developments
Software Engineer at Cake Solutions 12+ years of experience with JVM technologies Spring certified trainer 7+ years with Scala 5+ years with Kotlin funKTionale Arrow (funTKtionale + Kategory) RxKotlin original developer and former team leader Spring JDBC Kotlin support
Null Safety package org.cakesolutions.kotlin val hello0: String = "" val hello1: String = null //Null can not be a value of a non-null type String val hello2: String? = null val reversed0: String? = hello2?.reversed() val reversed1: String = reversed0.reversed()
Functions /** A function that takes 1 argument. */ public interface Function1 : Function { /** Invokes the function with the specified argument. */ public operator fun invoke(p1: P1): R }
Functions II fun doWithTwoNumbers(a: Int, b: Int, f: (Int, Int) Int): Int { return f(a, b) } fun main(args: Array) { val x = doWithTwoNumbers(2, 3, { a, b a + b }) doWithTwoNumbers(x, 3) { a, b a * b } }
Functions III Create your own control structures!! fun unless(conditional: Boolean, body: () Unit) { if (!conditional) { body() } } fun main(args: Array) { val age: Int = //Magic here! unless(age > 18) { //Play video games all day long } }
Delegated property lazy is NOT a language feature but a library function val lazyValue: String by lazy { println("computed") "Hello" } fun main(args: Array) { println(lazyValue) println(lazyValue) }
Extension functions III fun main(args: Array) { val myList = listOf(1, 2, 3, 4) //call to method reference .map(InttoString) .map { i i + i } .map(StringtoInt) .filter { it > 20 } // `it` is an implicit parameter println(myList) }
Combine all the things!!! one-line unless from Ruby!! infix fun (() Unit).unless(condition: Boolean) { if (!condition) { this() } } fun main(args: Array) { val age: Int = //Magic { /*pay taxes*/ } unless (age < 18) }
Inline fun time(body: () T): Pair { val startTime = System.currentTimeMillis() val v = body() val endTime = System.currentTimeMillis() return v to endTime - startTime } inline fun inTime(body: () T): Pair { val startTime = System.currentTimeMillis() val v = body() val endTime = System.currentTimeMillis() return v to endTime - startTime }
Inline III @NotNull public static final Pair time(@NotNull final Function0 extends T> body) { Intrinsics.checkParameterIsNotNull((Object)body, "body"); final long startTime = System.currentTimeMillis(); final Object v = body.invoke(); final long endTime = System.currentTimeMillis(); return (Pair)TuplesKt.to(v, (Object)(endTime - startTime)); } @NotNull public static final Pair inTime(@NotNull final Function0 extends T> body) { Intrinsics.checkParameterIsNotNull((Object)body, "body"); final long startTime = System.currentTimeMillis(); final Object v = body.invoke(); final long endTime = System.currentTimeMillis(); return (Pair)TuplesKt.to(v, (Object)(endTime - startTime)); } Decompiled bytecode
Inline IV public static final void main(@NotNull final String[] args) { Intrinsics.checkParameterIsNotNull((Object)args, "args"); final Pair b = time( (kotlin.jvm.functions.Function0>)_05_inlineKt$main$b._05_inlineKt$main$b$1.INSTANCE ); final long startTime$iv = System.currentTimeMillis(); Thread.sleep(1000L); final Object v$iv = "inline"; final long endTime$iv = System.currentTimeMillis(); final Pair i = TuplesKt.to(v$iv, (Object)(endTime$iv - startTime$iv)); System.out.println(b); System.out.println(i); }
Inline V static final class _05_inlineKt$main$b$1 extends Lambda implements Function0 { public static final _05_inlineKt$main$b$1 INSTANCE; @NotNull public final String invoke() { Thread.sleep(1000L); return "boring"; } static { _05_inlineKt$main$b$1.INSTANCE = new _05_inlineKt$main$b$1(); } }
Type-safe builders fun logged(body: Logger.() T): T { val log = LoggerFactory.getLogger("builder") return log.body() } fun main(args: Array) { val i = logged { info("THIS is INFO") debug("THIS is DEBUG") error("THIS is ERROR") 1 + 2 } }
Monitoring utils VisualVM class MonitorUtil { private val scanner = Scanner(System.`in`) fun awaitEnter(){ println("Press enter to continue") scanner.nextLine() } } fun monitored(body: MonitorUtil.() Unit) { val monitor = MonitorUtil() monitor.body() monitor.awaitEnter() }
Coroutines “..a coroutine is a very light thread that runs a block of code and has a similar life cycle, but can complete with a return value or an exception. Technically, a coroutine is an instance of a suspendable computation, a computation that may suspend. Coroutines aren't bound to a particular thread and can suspend in one Thread and resume execution in a different one” From the book Functional Kotlin
Coroutines IV Concept Description Coroutine Light thread Suspending function A function with a suspend modifier. It can suspend a coroutine without blocking the thread Suspending lambda A lambda function with a suspend modifier Coroutine builder A function that takes a suspending lambda Suspension point A point where a suspending function is invoked Continuation The state of a suspended coroutine at a suspension point
Actors I sealed class CounterMsg object IncCounter : CounterMsg() class GetCounter(val response: CompletableDeferred) : CounterMsg() fun counterActor(start: Int) = actor { var counter = start for (msg in channel) { when (msg) { is IncCounter counter is GetCounter msg.response.complete(counter) } } }
Other uses import arrow.core.Some fun main(args: Array) { val a = Some(1) val b = Some(2) val c = a.flatMap { x b.map { y x + y } } println("c = $c") }
Monadic comprehension import arrow.core.Option import arrow.core.Some import arrow.core.ev import arrow.core.monad import arrow.typeclasses.binding fun main(args: Array) { val a = Some(1) val b = Some(2) val c = Option.monad().binding { val x = a.bind() val y = b.bind() x + y }.ev() println("c = $c") } continuation: flatMap continuation: map