Arrow 0.12.0 & 0.13.1 is now available

Arrow 0.12.0 & 0.13.1 is now available

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.

Arrow Single Refactor

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.

Arrow Multiple Refactor

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.

Ensure the success of your project

47 Degrees can work with you to help manage the risks of technology evolution, develop a team of top-tier engaged developers, improve productivity, lower maintenance cost, increase hardware utilization, and improve product quality; all while using the best technologies.