Arrow 0.12.0 & 0.13.1 is now available
- •
- April 01, 2021
- •
- arrow• kotlin• functional programming
- |
- 8 minutes to read.
If you’re new to Arrow, it’s a group of open-source libraries that empower functional programming in Kotlin.
Many have been waiting for a stable Arrow 1.0.0 release for a long time. This dual release will finally pave the way to Arrow 1.0.0.
There are a couple of big changes, which do not affect the majority of users. If you’re not affected by these changes, we recommend jumping directly to 0.13.1
. If you are affected by these changes, you can upgrade to 0.12.0
, which offers @Deprecated
for all changed code and ReplaceWith
wherever possible. See below for more details on how you can refactor from 0.12.0
to 0.13.1
.
Arrow 1.0.0 will look roughly the same as 0.13.1, but with support for Kotlin MPP. With the IR backend stable in Kotlin 1.5, the Arrow Optics DSL kapt generator will also become a compiler plugin, and will also support Kotlin MPP.
Idiomatic FP in Kotlin
Arrow’s motto is, “A functional companion to the Kotlin Standard Library.” And, with 0.13.1
, we fully embrace this. In this patch release, we’ve deprecated Higher-Kinded Types, most type classes, and renamed several functions to align them with Kotlin’s Standard Library naming.
Version Highlights
0.12.0
- Add concrete implementations for traverse
- Arrow Fx Coroutines has out-of-the-box support for KotlinX Coroutines
- @Deprecated Higher Kinded Types
- @Deprecated all typeclasses except Semigroup, Monoid, & Semiring
- @Deprecated all extensions in
arrow.core.extensions.*
- @Deprecated Arrow Fx’s IO, RxJava, & Reactor
0.13.1
- Merge Arrow Core, Arrow Core Data, & Arrow Core Syntax
- Removal of all code deprecated in 0.12.0
Future of Arrow
0.13.1 serves as the model and proposed public API for Arrow’s first stable release, version 1.0.0.
Changes / Migration Guide
Many types have been deprecated in 0.12.0, making Arrow more Kotlin idiomatic and aligning Arrow with Kotlin’s Standard Library trajectory idioms and naming conventions, further deviating from the original Arrow encoding influenced by Haskell and Scala.
Extensions deprecation
arrow.core.extensions.*
APIs are deprecated and they have been flagged as @Deprecated
, including ReplaceWith
intentions wherever it was possible to make migrations for those easier. For APIs directly based on Kinds, see the section below.
Users may be able to refactor this automatically project-wide with the help of IDEA and the provided ReplaceWith
hints; unfortunately, we’ve found cases where manual adjustment is necessary.
Some functionality like traverse
or similar functionality that previously took a typeclass parameter is currently concretely implemented on the data types.
For example, the following traverse code:
val res: Either<String, List<Int>> =
listOf(1, 2, 3).traverse(Either.applicative()) { i ->
i.right()
}.fix().map { it.fix() }
Must be manually rewritten to the following:
val res: Either<String, List<Int>> =
listOf(1, 2, 3).traverseEither { i ->
i.right()
}
As you can see by the removal of the typeclass instance parameter, and higher kinded types, this code looks much better and much more Kotlin idiomatic. :tada:
If your project requires manual fixing after automatic replacement, check the other sections below for more details on how you might be able to fix these issues. Or swing by on KotlinLang Slack in the #arrow section.
Typeclass deprecation
All typeclasses that require Higher Kinded Types are deprecated, alongside Order
, Hash
, Show
, and Eq
. This only leaves Semigroup
, Monoid
, & Semiring
.
This is done partly because Kotlin doesn’t support a way to automatically provide implementations for typeclasses such as Scala, Swift, Rust, or other languages. Therefore, it’s always up to the user to manually/explicitly provide the instances.
Higher Kinded Type Typeclasses
These typeclasses are also deprecated because we’re deprecating Higher Kinded Types.
The methods of these typeclasses cannot be @Deprecated
with ReplaceWith
, so this requires manual refactoring to update to 0.13.1 code.
Polymorphic code like the following is no longer supported:
fun <F> Kind<F, Int>.addOne(FF: Functor<F>): Kind<F, Int> = FF.run {
map { it + 1 }
}
1.right().addOne(Either.functor())
1.some().addOne(Option.functor())
And will have to be manually rewritten to:
1.right().map { it + 1 }
1.some().map { it + 1 }
Order, Hash, Show, Eq
These typeclasses were removed in part due to the reasons explained above, but also because they duplicate the behavior of the Kotlin Language.
Kotlin follows the Java standards in their MPP philosophy where they embrace the Comparable
and Comparator
types.
So to bring Arrow closer to the languages, we’ve chosen to embrace the same strategies as the Kotlin Language, and we now implement compareTo
operator extensions for all data types in Arrow and cover the same functionality that Order
exposed on top of Comparable
.
Regardless of whether collection types or other types where Eq
, Hash
, or Order
may provide useful instances in practice, all existing compiled code in the standard library and other places in the ecosystem already rely on types being forced to implement Comparable
and override members like hashCode
and equals
.
Higher Kinded Type Deprecation
Higher Kinded type emulation is deprecated in Arrow in 0.12.0 and will be removed in 0.13.1. This was causing a heavy strain on the user to manually down-cast types and forcing users to use fix()
, especially in some of the more useful operators such as traverse, where they had to deal with nested downcasting as shown above.
This deprecation and removal shouldn’t hinder most users, unless you were writing polymorphic code with typeclasses, which is covered above.
Here are some tips if you need to rewrite something from Kind
to concrete code manually.
All Arrow data types implement Kind
in 0.12.0
. Let’s use Option
as an example.
-class ForOption private constructor() {
- companion object
-}
-typealias OptionOf<A> = arrow.Kind<ForOption, A>
-inline fun <A, B> OptionOf<A>.fix(): Option<A> = this as Option<A>
-sealed class Option<A> : OptionOf<A>
+sealed class Option<A>
Everywhere you currently use OptionOf
or fix
will become invalid in 0.13.1, but all functions returning OptionOf
will also be removed.
So, in general, you shouldn’t have to refactor any Kind code if you’ve followed the Extension
and Typeclass
steps above.
There is the exception of some of the data types that are being removed, that currently wrap Kotlin Standard Library types to make them Higher Kinded Types compatible.
Kind Wrappers ListK, SetK, MapK, & SortedMapK
The Kind wrappers are deprecated with the removal of Higher Kinded Types. All behavior that was added to the wrappers exists in arrow.core.*
as extension functions for the Standard Library types.
Similar to Higher Kinded types, these types shouldn’t require manual refactoring if you’ve followed the above-defined steps.
We may remove all calls to k()
, and add the missing imports or a wildcard import to arrow.core.*
. Most common methods in the Iterable
hierarchy like flatMap
, map
, and others are already provided by the Kotlin Standard library itself and don’t require imports.
Thanks for your interest in this new Arrow release! If you have any questions, please swing by the KotlinLang Slack #arrow
channel, and we’ll be happy to help address any specific issues with the migration.