Hi all - I’m new to FP in Kotlin (and in general :...
# functional
m
Hi all - I’m new to FP in Kotlin (and in general 😅) - Is it practical (from a performance and dev ergonomics standpoint) in Kotlin to use higher order functions and partial application to inject dependencies to aim for a functional approach? E.g. if I want to use a database connection in a getUsers function, is it performant to partially apply the database object then use the getUsers function that way? Or would this cause problems down the line and I should just stick to traditional dependency injection with a class constructor?
d
Hi, we use “pure” approach with higher order functions. Most our functions has following signatures:
Copy code
fun sth(
  dependency1: Dependency1,
  dependency2: Dependency2,
  ...
  param1: Param1,
  param2, Param2,
  ...
)
To define contract we use type aliases. Your case would look like this in our codebase:
Copy code
//API
typealias GetUser = (UserId) -> Either<StorageError, User>

//IMPL
fun getUseser(
  dbClient: DbClient,
  userId: UserId
): Either<StorageError, User> {
  //access DB, handle data & errors
}
We use Spring for bunding the application, so somewhere in configuration we would have:
Copy code
@Bean
fun getUserFun(dbClient: DbClient): GetUser = ::getUser.partially1(dbClient)

@Bean
fun someUseCaseFun(getUser: GetUser, ....): SomeUseCase = ::someUseCase.partially1(getUser)
We are quite happy with such approach.
Either
and
partially1
come of course from
Arrow
🙂.
You can use currying instead of partial application, but IDEA helps with partial application (provides information about expected type)
m
Thanks! Really cool use of type alias, this makes a lot of sense. Is Either different from Kotlin's result type much?
d
For
Result
you can only define the right side (positive result) - the left is bound to
Throwable
. So
Result
is like
Either<Throwable, T>
. In FP you should not work on exceptions -> every operation that may fail should return meaning full error which you can later handle or map to an error of “higher layer”. If some operation may fail we wrap it in
Either.catch
and use
mapLeft
to transform Throwable to custom error instance.
m
Makes sense, thank you!