|
| 1 | +--- |
| 2 | +title: Arrow 2.2.0 |
| 3 | +category: articles |
| 4 | +image: /img/arrow-release-ftr.jpg |
| 5 | +no_image_on_post: true |
| 6 | +tags: [core, articles] |
| 7 | +--- |
| 8 | + |
| 9 | +# Arrow 2.2.0 |
| 10 | + |
| 11 | +Arrow 2.2.0 is out, with improved and new functionality. |
| 12 | +This release builds on top of several [new features in Kotlin 2.2](https://kotlinlang.org/docs/whatsnew22.html), |
| 13 | +in its self-imposed role of _perfect companion for your Kotlin journey_. |
| 14 | + |
| 15 | +**`Raise` with context parameters.** |
| 16 | +The new package `arrow.core.raise.context` provides the same API as `arrow.core.raise`, |
| 17 | +but using context parameters instead of extension functions. |
| 18 | +This package is intended to be a full 1-1 replacement the extension-based API. |
| 19 | + |
| 20 | +Unfortunately, currently mixing `Raise` functions using extension-style and |
| 21 | +context-style doesn't lead to the better experience. Our advice is to fully migrate |
| 22 | +to the context-style API if possible, or stay completely within the extension style. |
| 23 | + |
| 24 | +```kotlin |
| 25 | +// extension-style |
| 26 | +fun Raise<PersonValidationError>.buildPerson(name: String, age: Int): Person { ... } |
| 27 | + |
| 28 | +// context-style, "fake" constructor |
| 29 | +context(Raise<PersonValidationError>) |
| 30 | +fun Person(name: String, age: Int): Person { ... } |
| 31 | +``` |
| 32 | + |
| 33 | +:::info Enabling context parameters |
| 34 | + |
| 35 | +In order to define functions with context parameters, you need to enable the |
| 36 | +corresponding language feature, as described in the |
| 37 | +[Kotlin documentation](https://kotlinlang.org/docs/whatsnew22.html#preview-of-context-parameters). |
| 38 | + |
| 39 | +::: |
| 40 | + |
| 41 | +**New `Racing` DSL for concurrency.** |
| 42 | +Arrow Fx provides high-level concurrency combinators |
| 43 | +to succinctly describe how tasks should be interleaved in a computation. |
| 44 | +Albeit useful, those combinators require nesting and writing your code in a |
| 45 | +particular way. In Arrow 2.2.0 we introduce a new |
| 46 | +[`Racing` DSL](/learn/coroutines/racing/#racing-dsl-experimental). |
| 47 | +Combined with the already existing |
| 48 | +[`AwaitAll` DSL](/learn/coroutines/parallel/#await-all--parallelism-experimental), |
| 49 | +you can write your coroutines code with little to no changes, while using as |
| 50 | +much concurrency as possible during execution. |
| 51 | + |
| 52 | +**`validate` for error values.** |
| 53 | +We have introduced a small utility function to bridge the world of validation functions |
| 54 | +working on `Raise`, and chained style using `Either` or `Option`. This function is |
| 55 | +called `validate`, and it should be commonly used in conjunction with `ensure` and similar functions. |
| 56 | + |
| 57 | +```kotlin |
| 58 | +fun failOnMoreConditionsWithBindMap(): Either<String, Int> = |
| 59 | + randomNumber() |
| 60 | + .validate { ensure(it != 10) { "Number 10 also not allowed" } } |
| 61 | + .map { it + 100 } |
| 62 | +``` |
| 63 | + |
| 64 | +This new function provides no functionality you could not get before. |
| 65 | +For example, here is the code equivalent to the one above, but using the `Either` DSL. |
| 66 | + |
| 67 | +```kotlin |
| 68 | +fun failOnMoreConditionsWithBindMap(): Either<String, Int> = either { |
| 69 | + val random = randomNumber().bind() |
| 70 | + ensure(random != 10) { "Number 10 also not allowed" } |
| 71 | + random + 100 |
| 72 | +} |
| 73 | +``` |
| 74 | + |
| 75 | +We acknowledge that the chain-of-calls style is a common one, and we want the Arrow API |
| 76 | +to appeal to users using their preferred style. |
| 77 | + |
| 78 | +**"At most once" for `Eval`.** |
| 79 | +Arrow provides the `Eval` type for [fine-grained control over evaluation](/learn/collections-functions/eval/). |
| 80 | +This is similar to `lazy` in the standard library, but you can choose |
| 81 | +between eager, lazy, and repeated (computed every time) evaluation strategies. |
| 82 | +However, there was no (easy) way to ensure that a computation was evaluated |
| 83 | +at most once. |
| 84 | + |
| 85 | +The new `Eval.atMostOnce` function (alongside `SuspendEval.atMostOnce`) |
| 86 | +provides this new behavior. You should be aware, though, that this means |
| 87 | +that getting the value of an `Eval` built this way may block (or suspend) |
| 88 | +if more than one thread does so concurrently. |
| 89 | + |
| 90 | +**Changes to `toString` for non-empty collections.** |
| 91 | +After a [long discussion in Slack](https://kotlinlang.slack.com/archives/C5UPMM0A0/p1757410910270849) |
| 92 | +it became clear that the behavior of `toString` for non-empty collections |
| 93 | +should just reflect that of the wrapped collection. Until now, using |
| 94 | +`NonEmptyList` or `NonEmptySet` added a prefix — from now on, we treat |
| 95 | +non-emptiness as simply a property of the collection, no different than other |
| 96 | +such as their size, that are not reflected when turning into a string. |
| 97 | + |
| 98 | +**New `arrow-core-result4k` module.** |
| 99 | +[Result4k](https://github.com/fork-handles/forkhandles/tree/trunk/result4k) |
| 100 | +is a popular library for computation that may succeed or fail. |
| 101 | +We now provide support for it as part of [typed errors](/learn/typed-errors/working-with-typed-errors/). |
| 102 | +You can either consume them — that is, `.bind()` a `Result` value — |
| 103 | +or produce them — use the `result4k` builder in a similar way to `either`. |
| 104 | + |
| 105 | +**Arrow Optics for Gradle, beta.** |
| 106 | +We have been working on a new approach to handle `@optics` annotations |
| 107 | +with much less configuration, and that removes the need for manually |
| 108 | +writing `companion object`s. This new approach is in beta, |
| 109 | +[read here](/community/blog/2025/11/01/arrow-optics-gradle/) all the details. |
| 110 | + |
| 111 | +**Migration to new plug-ins.** |
| 112 | +Following our _eager dependency update policy_, we have moved to the new recommended |
| 113 | +plug-ins in the ecosystem. |
| 114 | + |
| 115 | +- We now use [KSP2](https://github.com/google/ksp/blob/main/docs/ksp2.md), |
| 116 | +- Android now uses the [Android Gradle Library Plugin for KMP](https://developer.android.com/kotlin/multiplatform/plugin), |
| 117 | +- Binary validation is done using the [experimental built-in support](https://kotlinlang.org/docs/gradle-binary-compatibility-validation.html), |
| 118 | +- We now publish a [version catalog](https://docs.gradle.org/current/userguide/version_catalogs.html#sec:importing-published-catalog) |
| 119 | + for consistent versioning of Arrow dependencies. |
| 120 | +- The [Arrow plug-in for IntelliJ IDEs](https://plugins.jetbrains.com/plugin/24550-arrow) |
| 121 | + now supports up to 2025.3, and understands code using context parameters |
| 122 | + and the new `Racing` DSL. |
0 commit comments