https://kotlinlang.org logo
Join Slack
Powered by
# arrow
  • m

    Marc

    04/22/2025, 10:01 AM
    hey guys,
    kotest-extensions-arrow
    have ben move to read only. could someone tell me what i the alternative we have to use now? šŸ™šŸ»
    p
    • 2
    • 3
  • e

    Emil Kantis

    04/22/2025, 2:18 PM
    I'm getting issues when trying to serialize a non-empty list using Jackson. (Arrow 2.1.0, Jackson 2.18.3)
    āœ… 1
    a
    • 2
    • 5
  • a

    Alejandro Serrano.Mena

    04/22/2025, 7:08 PM
    more releases this week: Arrow plug-in for IntelliJ now features gutter icons for
    Raise
    https://arrow-kt.io/community/blog/2025/04/22/arrow-intellij-0-3/
    arrow intensifies 7
    K 11
    🤩 4
    amaze 1
    e
    l
    • 3
    • 16
  • a

    Artūras Šlajus

    04/23/2025, 9:08 AM
    Hey. Kotlin doesn’t have union types, right? I can’t take do this, right?
    Copy code
    val v1: Validator<E1>
    val v2: Validator<E2>
    
    listOf(v1, v2): List<Validator<E1 | E2>>
    a
    j
    • 3
    • 12
  • f

    Fred Friis

    04/25/2025, 3:36 PM
    trying to add Arrow 2.1.0 to one of our repos and getting this error (more in screenshots)
    Copy code
    some kotlin runtime libraries have an unsupported binary format
    Copy code
    some kotlin runtime libraries and 6 other jars have an unsupported binary format
    my understanding is this repo has kotlin 1.9 so what's the dealio?
    a
    p
    • 3
    • 3
  • a

    aykrieger

    04/26/2025, 2:27 AM
    Hi all, I would like to use the concept of "errors as values" instead of throwing exceptions when I validate the data of a newly instantiated class. Before, to ensure my data was validated I would use the
    init{ }
    block and this would throw an exception if the data given in the constructor was invalid. Example:
    Copy code
    @JvmInline
    value class Foo(
        val bar: String,
    ) {
        init {
            require(bar.isNotBlank())
        }
    }
    I was thinking I could use the
    Either
    class and a companion object to validate the data when calling
    create
    without throwing an exception.
    Copy code
    @JvmInline
    value class Foo(
        val bar: String,
    ) {
        companion object {
            fun create(bar: String): Either<Error, Foo> =
                if (bar.isNotBlank()) {
                    Foo(bar).right()
                } else {
                    IsBlankString().left()
                }
            }
        }
    }
    
    sealed interface Error {
        class IsBlankString: Error
    }
    The issue is that I can't make the
    Foo
    constructor
    Foo(val bar: String)
    private for
    value class
    or
    data class
    . So I can't guarantee that the property
    bar
    has been validated if someone creates
    Foo
    with
    Foo("")
    instead of
    Foo.create("")
    . I tried changing the function name from
    create
    to
    invoke
    to possibly override the constructor but it seems the Kotlin compiler picks the constructor
    Foo(val bar: String)
    instead of the
    invoke
    function when calling
    Foo("")
    . I understand I can achieve this with a regular
    class
    and use a private constructor, but I haven't been able to achieve this with a
    value class
    or
    data class
    . I would like have the auto-generated
    copy()
    and
    equals()
    functions that
    data classes
    provides. I read this article and they have an interesting solution for this issue by using a
    sealed interface
    to validate a
    data class
    . When I tried this solution, I wasn't able to use the
    .copy()
    function normally auto-generated for
    data class
    . So there are some tradeoffs. Link: https://proandroiddev.com/how-to-use-arrows-either-for-exception-handling-in-your-application-a73574b39d07 Does anyone have any recommendations or solutions you have used to solve this issue?
    e
    a
    a
    • 4
    • 6
  • a

    Alen Mujezinovic

    04/29/2025, 2:57 PM
    Hey folks. Has someone considered the use case of using optics together with
    private constructor
    and
    @ConsistentCopyVisibility?
    There are cases where
    copy
    should only be available to other methods of the class and therefore be private, e.g. when modelling state changes that require $otherThings to happen before
    copy
    can be safely called.
    y
    • 2
    • 2
  • a

    Alejandro Serrano.Mena

    04/29/2025, 3:26 PM
    there is a new 2.1.1 release of Arrow! this is mostly a bugfix release: • fixed problems with Jackson serialization • made it possible to use Arrow with Android SDK > 21 (before it was >24) we also added a new wrapAsNonEmpty family of functions to avoid copying when creating a NonEmptyThing
    arrow intensifies 9
    s
    • 2
    • 2
  • c

    carbaj0

    04/30/2025, 5:54 AM
    I understand that in the final version of the context parameters this will not be an error, right?
    s
    p
    • 3
    • 6
  • y

    Youssef Shoaib [MOD]

    04/30/2025, 9:29 AM
    A fun oddity:
    AutoCloseScope
    can do reverse-mode automatic differentiation:
    Copy code
    interface AD<Num> {
      val Double.num: Num
      val Int.num: Num get() = toDouble().num
      operator fun Num.plus(other: Num): Num
      operator fun Num.times(other: Num): Num
      fun exp(x: Num): Num
    }
    data class NumB(val value: Double, var d: Double)
    
    fun backwardsAutoClose(x: Double, prog: AD<NumB>.(NumB) -> NumB): Double {
      val input = NumB(x, 0.0)
      autoCloseScope {
        val res = object : AD<NumB> {
          override val Double.num: NumB get() = NumB(this, 0.0)
          override fun NumB.plus(other: NumB) = NumB(value + other.value, 0.0).also { z ->
            onClose {
              this.d += z.d
              other.d += z.d
            }
          }
    
          override fun NumB.times(other: NumB) = NumB(value * other.value, 0.0).also { z ->
            onClose {
              d += other.value * z.d
              other.d += value * z.d
            }
          }
    
          override fun exp(x: NumB): NumB {
            val xExp = mathExp(x.value)
            val z = NumB(xExp, 0.0)
            onClose { x.d += xExp * z.d }
            return z
          }
        }.prog(input)
        res.d += 1
      }
      return input.d
    }
    arrow intensifies 1
    K 1
  • g

    gpopides

    04/30/2025, 11:53 AM
    not sure what the issue is, but the docs here seem a bit off regarding the type parameter A https://apidocs.arrow-kt.io/arrow-fx-coroutines/arrow.fx.coroutines/closeable.html
    s
    • 2
    • 4
  • e

    Edgar Avuzi

    05/02/2025, 6:10 AM
    Is there a doc, guide or article on how to manage stacktrace while working with https://arrow-kt.io/learn/typed-errors/ ?
    y
    s
    • 3
    • 10
  • y

    Youssef Shoaib [MOD]

    05/03/2025, 11:55 PM
    Raise proves the law of the excluded middle (well, something equivalent to it anyway)!
    Copy code
    inline fun <A> doubleNegationElimination(block: ((A) -> Nothing) -> Nothing): A = merge { block(this::raise) }
    For more info Bonus:
    suspend
    allows the same thing (which is precisely why early raise builders were made using
    suspend
    magic):
    Copy code
    suspend fun <A> doubleNegationElimination(block: suspend (suspend (A) -> Nothing) -> Nothing): A = suspendCoroutine { cont ->
        block.startCoroutine({ value ->
            suspendCoroutine<Nothing> {
                cont.resume(value)
            }
        }, cont)
    }
    arrow intensifies 1
    s
    • 2
    • 2
  • m

    Marc

    05/07/2025, 2:34 PM
    doesn’t feel a bit odd using the Raise api with context params? with context receivers was feeling way more natural IMO
    Copy code
    context(raise: Raise<DomainError>)
    fun <T> HttpClient.getSomethingFromNetwork(): T = with(raise) {
        // network operator | raise(DomainError)
    }
    not sure if that’s the only way tho , but it feels odd the need to scope raise now šŸ˜•
    a
    • 2
    • 2
  • s

    Stephen Morse

    05/15/2025, 2:53 PM
    Can anyone here tell me how significant the binary compatibility issues are for
    NonEmptyList
    (using
    NonEmptyListSerializer
    ) between Arrow v1 and v2? My company (Cash App/Block) has some data serialized with the
    NonEmptyListSerializer
    of Arrow v1, but we need to upgrade to Arrow v2. Is it possible to define a serializer that can deserialize both the v1 and v2 binary formats? šŸ¤”
    y
    p
    +2
    • 5
    • 8
  • d

    dawidhyzy

    05/16/2025, 8:15 AM
    Is it possible to recover from multiple errors with raise? For example having such function:
    Copy code
    context(_: Raise<StreamError>, _ : Raise<ServiceError.Expected>)
    suspend fun getLiveStream(url: ChannelStreamUrl): Stream
    a
    y
    • 3
    • 6
  • a

    Alejandro Serrano.Mena

    05/16/2025, 2:36 PM
    new 2.1.2 released! it has a few bug fixes, and lowers the required JVM to 1.8 (except for the Compose module)
    K 4
    arrow intensifies 11
  • g

    Geert

    05/20/2025, 7:40 AM
    Hi, I’m a bit stuck on optics, I’m trying to ā€œmatchā€ the last element of an array, from within a copy method, something like this:
    Copy code
    person.copy {
        Person.names.last transform { it.replaceFirstChar(Char::uppercase) }
    }
    Of course the
    last
    val does not exist, but is there some way to do this?
    a
    • 2
    • 2
  • j

    jean

    05/23/2025, 10:50 AM
    Does anyone has insights in the ā€œRich errorsā€ feature that was announced? It looked similar to what
    Either
    does, didn’t it?
    d
    e
    +3
    • 6
    • 10
  • y

    Youssef Shoaib [MOD]

    05/25/2025, 8:27 PM
    Raise
    can be used to implement first-class generic lambdas (i.e rank-2 polymorphism)!
    Copy code
    import arrow.core.raise.Raise
    import arrow.core.raise.merge
    
    private fun main() {
      println("Identity:")
      useIdentity {
        raise.raise(value)
      }
      println("ListMaker: ")
      useListMaker {
        // "opening" an existential type
        // ideally, this would work like the example above through compiler magic
        fun <A> ListMaker<A>.block(): Nothing = raise.raise(listOf(value))
        block()
      }
      useListMaker {
        fun <A> ListMaker<A>.dishonest(): Nothing = when (value) {
          is Unit -> raise.raise(listOf())
          is Int -> raise.raise(listOf(value))
          else -> raise.raise(listOf(value, value))
        }
        dishonest()
      }
      println("Choice: ")
      useChoice {
        raise.raise(second)
      }
      useChoice {
        fun <A> Choice<A>.dishonest(): Nothing = when (first) {
          is Unit -> raise.raise(second)
          is Int -> raise.raise(first)
          else -> raise.raise(second)
        }
        dishonest()
      }
    }
    
    private class Identity<A>(val value: A, val raise: Raise<A>)
    
    private fun useIdentity(block: Identity<*>.() -> Nothing) {
      val value = merge {
        Identity(Unit, this).block()
      }
      println(value)
      val value2 = merge {
        Identity(42, this).block()
      }
      println(value2)
    }
    
    private class ListMaker<A>(val value: A, val raise: Raise<List<A>>)
    
    private fun useListMaker(block: ListMaker<*>.() -> Nothing) {
      // we can convert this to a List<Unit>, which is equivalent to an Int
      val listValue = merge {
        ListMaker(Unit, this).block()
      }
      println(listValue)
      val listValue2 = merge {
        ListMaker(42, this).block()
      }
      println(listValue2)
      // We can always keep the polymorphic function honest by wrapping in an unreachable type
      // Using data class for clarity, but ideally you want a type that returns the same
      // toString and same hashCode for all instances.
      data class Wrapper<A>(val value: A)
    
      val wrappedValue = merge {
        ListMaker(Wrapper(Unit), this).block()
      }
      println(wrappedValue)
      // hence it can't know the type of the value inside without reflection
      // (but with reflection, all bets are off anyway)
      val wrappedValue2 = merge {
        ListMaker(Wrapper(42), this).block()
      }
      println(wrappedValue2)
    }
    
    private class Choice<A>(val first: A, val second: A, val raise: Raise<A>)
    
    private fun useChoice(block: Choice<*>.() -> Nothing) {
      // we can convert this to a Boolean
      val value = merge {
        Choice(false, true, this).block()
      }
      println(value)
      val value2 = merge {
        Choice(41, 42, this).block()
      }
      println(value2)
      // Keeping it honest, just like in ListMaker
      data class Wrapper<A>(val value: A)
    
      val wrappedValue = merge {
        Choice(Wrapper(false), Wrapper(true), this).block()
      }
      println(wrappedValue)
      // so results are identical here
      val wrappedValue2 = merge {
        Choice(Wrapper(41), Wrapper(42), this).block()
      }
      println(wrappedValue2)
    }
    It turns out we can very easily implement generic lambdas (i.e. lambdas like
    <A> (A) -> List<A>
    ) without direct language support! Of course, we could already use a (not-
    fun
    )
    interface ListMaker { fun <A> make(a: A): List<A> }
    , but that'd require making an anonymous object at the call site, which has awkward syntax, and cannot be made
    inline
    . Instead, we can define it directly by giving the lambda only one way to exist, which is to
    raise
    something of an existentially-quantified type, while also potentially giving it several members of that unknown type. Sadly, the compiler isn't super smart at the moment in dealing with existential types. It can handle some of them in very, very simple cases (as shown in the
    useIdentity
    example), but it gives up whenever there's any function call in between (like
    listOf
    , for instance). Hopefully the compiler can get smarter in the future!
    🧵 1
    šŸ‘€ 1
    • 1
    • 2
  • j

    jean

    05/30/2025, 7:28 AM
    I’m migrating an old codebase from 1.1.5 to 2.1.2. What’s a good replacement for
    parTraverse
    ? I see the migration guide recommands
    mapOrAccumulate
    but does it have the
    parrallelle
    capabilities too?
    s
    • 2
    • 6
  • d

    dave08

    06/05/2025, 4:39 PM
    Is there any recoverCatching in the Either.catch api (something like in Kotlin's Result, where you can chain a few potentially failing operations and still have a fallback), w/o nesting catches?
    s
    c
    • 3
    • 14
  • j

    J.D. Satlin

    06/10/2025, 12:42 AM
    I've found myself reaching for and unable to find a totally comfortable way to take an already existing either's right value, and under some condition turn it into a value in the left channel. Sort of the opposite of a
    recover
    . Sometimes this is a sign to turn a function into one that takes a raise context overall, but sometimes that feels less advisable (public functions, that then become less discoverable because they require the raise context, mostly. That might be its own discussion). About the simplest version I've got is below, but I'm wondering if there's just something I'm missing in how to do this more easily than a flatmap?
    Copy code
    fun randomNumber(): Either<String, Int> {
        val randomNum = Random(1).nextInt(1..10)
    
        return if (randomNum > 5) {
            randomNum.right()
        } else {
            "The number was too low".left()
        }
    }
    
    fun failOnMoreConditions(): Either<String, Int> {
        return randomNumber()
            .flatMap { num ->
               either {
                   ensure(num != 10) { "Number 10 also not allowed" }
                   num
               }
        }
    }
    y
    a
    • 3
    • 16
  • s

    S.

    06/11/2025, 3:04 PM
    How do I correctly use
    either {}
    in combination with
    flow {}
    ? when I have a function like this
    Copy code
    fun list(): Either<Error, Flow<Item>> = either { 
        flow {
            if (someSuspendFun()) this@either.raise(Error)
        emitAll(someList())
        }
    }
    it says
    arrow.core.raise.RaiseLeakedException: 'raise' or 'bind' was leaked outside of its context scope. Make sure all calls to 'raise' and 'bind' occur within the lifecycle of nullable { }, either { } or similar builders.
    or is the way to go to make the function suspend and do the check before the flow block?
    s
    • 2
    • 4
  • e

    Erik Dreyer

    06/12/2025, 4:19 PM
    When using
    Either.catch()
    I find myself wanting to treat it like
    either {}
    and use various DSL methods provided by
    Raise
    inside the catch() function. Since it doesn't provide that context, is this the correct way?
    Copy code
    either {
        Either.catch() { ... }.bind()
    }
    y
    s
    • 3
    • 10
  • k

    Kjartan

    06/25/2025, 5:50 AM
    Does anyone know if the new DI feature introduced in Ktor 3.2.0 will replace the need for using Arrows SuspendApp with Ktor lib?
    s
    • 2
    • 4
  • k

    Kev

    06/30/2025, 6:28 AM
    In Arrow 1.2.4, why is the construction of CircuitBreaker a suspendable function? What strategy can I use to create a shared CircuitBreaker to be used across multiple API method calls?
    s
    • 2
    • 3
  • m

    Michael Friend

    07/01/2025, 6:30 PM
    Posted this as a comment on the PR for raise context param support but figured id crosspost here to start a conversation and see if anyone has workaround ideas. TLDR with an inline function that takes a
    block: context(Raise<Error>) () -> T
    parameter, calling the function within an
    either
    builder causes some ambiguity between the extension function raise variants like
    Raise<E>.raise()
    you can call on the receiver on the
    either
    block and the
    context(Raise<E>) raise()
    variant available on the context parameter on block which makes it easy to raise an error on the either block rather than within the block parameter
    • 1
    • 3
  • o

    Olaf Gottschalk

    07/08/2025, 3:18 PM
    I got a question regarding resources for you. In my use case, I have an application that has to start/manage/shutdown entities called
    Server
    - which is defined as an
    interface
    . So it looks along the lines of this:
    Copy code
    interface Server {
      fun prepare()
      fun run()
      fun shutdown()
    }
    In order to properly handle these as resources, I have some
    fun execute()
    that does this:
    Copy code
    fun execute() {
      resourceScope {
        servers.forEach {
          install({ it.prepare() }, { _, _ -> it.shutdown() })
        }
        servers.forEach(Server::run)
      }
    }
    Now, this assumes that all
    Server
    classes basically can do all of there setup in
    prepare
    and properly release all resources in
    shutdown
    . In some servers though, I would like to also use the resource concept and install things in the same resource scope to allow them to live alongside the servers and properly get shutdown as well. Those types of server implementations typically do not define any code in their
    shutdown
    function, but they want to install more resources in the same resource scope. That's why I extended my
    prepare
    fun like this:
    Copy code
    interface Server {
      context(ResourceScope) fun prepare()
      fun run()
      fun shutdown()
    }
    To now execute my system, I need to manually bring the resource scope back into scope:
    Copy code
    fun execute() {
      resourceScope {
        servers.forEach {
          install({ context(this@resourceScope) { it.prepare() } }, { _, _ -> it.shutdown() })
        }
        servers.forEach(Server::run)
      }
    }
    Now the big question: am I doing something wrong? Is it safe to hand in the same resource scope into the acquire step of a resource so this resource can also install resources in the same scope? Note: the reason I do this is that I got several different types of Server implementations, some that need a "classic" prepare/shutdown step, others that are fine with installing resources!
    s
    y
    a
    • 4
    • 12
  • r

    raulraja

    07/17/2025, 5:19 PM
    https://deepwiki.com/arrow-kt/arrow This works surprisingly well to get info about arrow's apis
    arrow intensifies 2
    y
    • 2
    • 2