Slide 1

Slide 1 text

The Functional Fix: Kotlin Error Handling Made Elegant @harikrishnan83

Slide 2

Slide 2 text

© 2025 All Rights Reserved Http Request Problem Statement { "URL": "/items", "method": "POST", "body": { "id": "1", "name": ”item 1", "price": 19.99 } } Http Stub Http Request { "URL": "/items", "method": "POST", "body": { "id": ”2", "name": ”item 2", "price": 29.99 } } MATCH

Slide 3

Slide 3 text

© 2025 All Rights Reserved Http Request 1 { "URL": "/items", "method": "POST", "body": { "id": "1", "name": ”item 1", "price": 19.99 } } Problem Statement – Match HTTP Requests Http Request 2 { "URL": "/items", "method": "POST", "body": { "id": ”2", "name": ”item 2", "price": 29.99 } } Result: Failure, Message: Body did not match

Slide 4

Slide 4 text

© 2025 All Rights Reserved Solution: As per our mental model matchUrl matchMethod matchBody

Slide 5

Slide 5 text

© 2025 All Rights Reserved Solution: Procedural Code class HttpRequest(private val url: String, private val method: HttpMethod, private val body: String) { fun matches(anotherRequest: HttpRequest): Result { if (this.url != anotherRequest.url) return Failure("URL did not match.") if (this.method != anotherRequest.method) return Failure("Method did not match.") if (this.body != anotherRequest.body) return Failure("Body did not match.") return Success("everything matches") } }

Slide 6

Slide 6 text

© 2025 All Rights Reserved Solution: mental model vs conditional code matchUrl matchMethod matchBody !(matchUrl) !(matchMethod) !(matchBody) Failure Failure Failure Success

Slide 7

Slide 7 text

Railway Oriented Programming Dual track approach to focus on the “Happy Path”

Slide 8

Slide 8 text

Functional approach to error handling The Railway Analogy “Many examples in functional programming assume that you are always on the “happy path”. But to create a robust real world application you must deal with validation, logging, network and service errors, and other annoyances. So, how do you handle all this in a clean functional way? This talk will provide a brief introduction to this topic, using a fun and easy-to-understand railway analogy.” Blog Post - https://fsharpforfunandprofit.com/rop/ NDC London 2014 - https://vimeo.com/113707214 Scott Wlaschin Attribution - https://ddd.academy/scott-wlaschin/

Slide 9

Slide 9 text

© 2025 All Rights Reserved Applying the ROP analogy to our problem

Slide 10

Slide 10 text

Code walkthrough Step by step transformation to Railway Oriented Programming

Slide 11

Slide 11 text

Introducing Monads Either Monad and the Flatmap

Slide 12

Slide 12 text

© 2025 All Rights Reserved Monadic Curse A Monad is just a monoid in the category of endofunctors “The monadic curse is that once someone learns what monads are and how to use them, they lose the ability to explain them to other people” - https://old.arrow-kt.io/docs/patterns/monads/#the- fallacy-of-monad-tutorials

Slide 13

Slide 13 text

© 2025 All Rights Reserved An oversimplified way to understand Either Wrapper around raw values that allows a bind transformation Raw values • Right – Http Request • Left – Error Message Bind transformation • FlatMap

Slide 14

Slide 14 text

© 2025 All Rights Reserved FlatMap – The bind transformation • Input – Function that accepts unwrapped value of Either • Responsibility – Apply this function on wrapped value of Either • Output – Another Monad Example:

Slide 15

Slide 15 text

© 2025 All Rights Reserved Why take all this trouble? matchUrl(request).flatMap { matchBody(it) }.flatMap { match... }... The ability to compose functions is simply too good to resist. How does this even work? • Either Monad is Right Biased • FlatMap in Either only applies the function on the right (yes that function which accepts the unwrapped value of Either)

Slide 16

Slide 16 text

Sounds familiar? f >=> g >=> h Right Fish Operator or Kleisli Composition - >=> It allows chaining functions that return a monad (e.g., Either, Option, Result), effectively composing functions of type A -> M Heinrich Kleisli Attribution: Konrad Jacobs, GFDL , via Wikimedia Commons

Slide 17

Slide 17 text

© 2025 All Rights Reserved FlatMap and Fold Wait, but what about errors? Either.Fold takes two functions • ifLeft • ifRight Applying it to our use case matchUrl(request).flatMap { matchBody(it) } .fold({ Failure(it) }, { Success(it) })

Slide 18

Slide 18 text

© 2025 All Rights Reserved Putting it all together matchUrl(anotherRequest).flatMap { matchMethod(it) }.flatMap { matchBody(it) }.fold( { Failure(it) }, { Success(it) } )

Slide 19

Slide 19 text

© 2025 All Rights Reserved Machinery Business End A minor change in formatting matchUrl(anotherRequest) .flatMap { matchMethod(it) }.flatMap { matchBody(it) }.fold( { Failure(it) }, { Success(it) } )

Slide 20

Slide 20 text

Extracting the error handling Bringing back ”then” and “handleError”

Slide 21

Slide 21 text

© 2025 All Rights Reserved

Slide 22

Slide 22 text

Thanks @harikrishnan83 Sample Code - https://github.com/harikrishnan83/RailwayOrientedProgramming