Slide 1

Slide 1 text

Karin-Aleksandra Monoid GDG Nuremberg, 2021 Hands-on Arrow (How we filled Kotlin standard library gaps without converting code to Scala)

Slide 2

Slide 2 text

Agenda ● What is Arrow? ● NonEmptyList ● Either ● Monad Comprehensions

Slide 3

Slide 3 text

What is Arrow?

Slide 4

Slide 4 text

What is Arrow? 4 4 Core FX Optics Meta

Slide 5

Slide 5 text

What is Arrow? 5 5 Core FX Optics Meta

Slide 6

Slide 6 text

NonEmptyList

Slide 7

Slide 7 text

Non-empty list Is JSON {“payments”: []} ok? 7 7 Payments List of items (Phone, Reference, Amount) Phone ... String(100) Required Reference ... String(100) Required Amount ... Decimal Required

Slide 8

Slide 8 text

Non-empty list NonEmptyList.of() // does not compile NonEmptyList.of(1, 2, 3, 4, 5) // NonEmptyList 8 8

Slide 9

Slide 9 text

Non-empty list NonEmptyList.of() // does not compile NonEmptyList.of(1, 2, 3, 4, 5) // NonEmptyList 9 9

Slide 10

Slide 10 text

Either

Slide 11

Slide 11 text

Java Exceptions if (somethingWrong) throw new SomeException(...) 11 11

Slide 12

Slide 12 text

Java Exceptions - “Handling” in signature void testFun() throws SomeException 12 12

Slide 13

Slide 13 text

Java Exceptions - Handling with try try { testFun() } catch (SomeException e) { ... } 13 13

Slide 14

Slide 14 text

Java Exceptions IntStream.range(0, 10) .forEach(i -> testFun()) 14 14

Slide 15

Slide 15 text

Java Exceptions IntStream.range(0, 10) .forEach(i -> testFun()) 15 15

Slide 16

Slide 16 text

Java Exceptions IntStream.range(0, 10) .forEach(hideException(i -> testFun())); 16 16

Slide 17

Slide 17 text

Java Exceptions unhideSomeException(() -> IntStream.range(0, 10) .forEach( hideException(i -> testFun() ))); 17 17

Slide 18

Slide 18 text

Kotlin Exceptions ● No more checked exceptions (like Scala, Groovy and everyone else) 18 18

Slide 19

Slide 19 text

Kotlin Exceptions (1 until 10).forEach { testFun() } 19 19

Slide 20

Slide 20 text

Null fun String.toIntOrNull(): Int? ● Not expressive ● ????? ● null-checks 20 20

Slide 21

Slide 21 text

Result Type inline class Result : Serializable 21 21

Slide 22

Slide 22 text

Result Type 22 22 fun deserialize(): Something { return try { doSomething() } catch (_: Exception) { try { doSomethingElse() } catch(_: Exception) { doSomethingElseAgain() }}... fun deserialize(): Something { return runCatching { doSomething() }.recoverCatching { doSomethingElse() }.getOrElse { doSomethingElseAgain() } }

Slide 23

Slide 23 text

Sealed Type sealed class Result class Success : Result() class FullMoonFailure : Result() class ElonMuskTweetedFailure : Result() 23 23

Slide 24

Slide 24 text

Either sealed class Either 24 24

Slide 25

Slide 25 text

Validated sealed class Validated 25 25

Slide 26

Slide 26 text

Validated vs Either ● Either stops at first fail, validated collects all: User(phone, name, age) User(“test”, XÆA-12 Musk, -10) ● Either: invalid phone ● Validated: invalid phone, name*, age 26 26 * https://www.kalzumeus.com/2010/06/17/falsehoods-programmers-believe-about-names/

Slide 27

Slide 27 text

Monad comprehensions

Slide 28

Slide 28 text

Require requireNotNull(request.userId) requireNotNull(request.transaction.id) 28 28

Slide 29

Slide 29 text

Require public inline fun requireNotNull (value: T?): T { contract { returns() implies (value != null) } return requireNotNull(value) { "Required value was null." } } 29 29

Slide 30

Slide 30 text

if-else-if-else-if-else if(request.userId == null) return buildExceptionResponse(...) if(request.transaction.id == null) return buildExceptionResponse(...) ... 30 30

Slide 31

Slide 31 text

Arrow Monads 31 31 https://chrisdone.com/posts/monads-are-burritos/

Slide 32

Slide 32 text

Arrow Monads 32 32 inline fun Iterable.flatMap( transform: (T) -> Iterable ): List

Slide 33

Slide 33 text

Chaining - flatMap val response = checkForNull(...) .flatMap { userId -> checkForNull(...).flatMap { paymentId -> checkForNull(...).flatMap { items -> checkForNull(...).flatMap { status -> checkForNull(...).map { ( … )}}}}}}}}} 33 33

Slide 34

Slide 34 text

Chaining - monad comprehensions val response = Either.fx { val userId = checkForNull(request.userId).bind() val paymentId = checkForNull(request.transaction.id).bind() val items = checkForNull(request.transaction.items).bind() val status = client.checkPaymentStatus(userId,...) // ... } return response.getOrHandle { it } private fun checkForNull(param: T?, paramName: String): Either 34 34

Slide 35

Slide 35 text

No content