Skip to main content

Arrow 1.2.3 release

· 5 min read

We are happy to announce the availability of version 1.2.3 of the Arrow collection of libraries. According to our plan, this is the last non-bugfix release of the 1.x series. From now on, our main branch targets Arrow 2.0, which should be the next major release.

We are incredibly thankful to the many people that have contributed to this release, bringing new ideas and quite some code.

Please use 1.2.4

Version 1.2.3 of arrow-core changed the behavior of Raise computations returning functions or sequences. This change restricted some useful usages, so the team has decided to roll it back and keep the 1.2.1 behavior.

New features

A version number like 1.2.3 sounds like a small bugfix release, but this is far from truth in this case: this release is full of new modules to help you be productive when writing Kotlin.

Improved focus on Compose

Arrow provides building blocks relevant to many projects using Kotlin. A large part of our community is doing frontend work, and during the latest months, the team has been trying to understand their needs, in order to make Arrow a relevant tool in that space.

From that journey, we have put together a new documentation page highlighting different ways in which Arrow may be useful in your Compose application. There is also a new arrow-optics-compose module that includes utilities to work with immutable data inside a MutableState or MutableStateFlow.

We are eager to hear more use cases or needs where Arrow may help the lives of Kotlin developers. Feel free to drop by the #arrow channel in the Kotlin Slack, or open an issue or discussion in our repository.

Non-suspend resource management

Resource safety in Arrow has been traditionally tied to the use of coroutines and suspend functions. This is the right choice for Kotlin-first libraries, like Ktor or Koin, but many libraries still come from a Java background where no such feature exists. Beginning with this version, we provide two "variations" of resource management:

  • Resource, from the arrow-fx-coroutines module, is based on suspend and ensures the desired behavior alongside coroutines (including cancellation).
  • AutoClose, from the new arrow-autoclose module, provides almost the same API as Resource, but without the suspend requirement.

Forward compatible Eval

One of our goals is to make the transition to 2.0 as smooth as possible. You can already migrate to the new APIs by using Arrow 1.2.3, and then ensuring that you get no deprecation warnings.

During this process, we were made aware that there was no clear story for the migration of Eval. On the other hand, the use cases are very narrow. The decision was to create a new arrow-eval module, present since this release, and mark the one from arrow-core point the new module, instead of entirely removing this functionality from Arrow.

Collectors

The new arrow-collectors module allows composing operations over sequences of values (lists, flows, sequences) while ensuring that the sequence is traversed only once. This property is especially relevant when building the sequence is expensive, or simply cannot be reproduced, like a stream of data from a database or a flow of actions.

Improved features

Several features in the library have been improved, to ensure that Arrow covers a variety of use cases.

Lenses for sealed classes

This was once of the older feature requests still in our issue tracker, which is now closed thanks to a wonderful contribution!

From now on, the Optics KSP plug-in can generate lenses for sealed hierarchies, given that the field lives in the common parent. For example, the following code

@optics sealed interface User {
val name: String

data class Person(override val name: String, val age: Int): User
data class Company(override val name: String, val vat: VATNumber): User
}

generates from this version on both prisms for each choice, and a lens for name.

Higher-arity functions

We have traditionally been reluctant to add variations of zip with more than 10 parameters, because we felt that the narrow use cases did not balance out the increase in binary size. Since this release Arrow provides those functions in a new arrow-core-high-arity module.

More accumulating functions for Raise

Typed errors provide two essential ways to accumulate errors: zipOrAccumulate and mapOrAccumulate. Those correspond to accumulating over a fixed number of computations of different types, or accumulating over an unknown quantity of computations with the same type.

The mapOrAccumulate function always returns a new list. In some cases, you don't really care about this result, just about the iteration behavior. This is similar to the different between map and forEach in the standard library. From there Arrow takes the name of the new function: forEachAccumulating.

One potential use case is performing validation over elements of a list, but keeping the values intact.

people.forEachAccumulating { person ->
ensure(person.age >= 0) { InvalidAge(person.name) }
}

Better memoization

MemoizedDeepRecursiveFunction is a powerful tool to express recursive algorithms without worries over stack overflow or recomputation. However, there was a lack of control over how memoized values were stored or evicted, which made the type less useful than intended.

From this release on, there are new overloads to support custom memoization policies. Furthermore, the new arrow-cache4k module provides integration with the excellent cache4k library.

More integrations

Although not part of this release, we would like to highlight that Akkurate, which provides a wonderful DSL for validation over data, has released an integration module for Arrow. This adds to the rest of integrations and shows the collaborative spirit of the Kotlin community.