-
Notifications
You must be signed in to change notification settings - Fork 21
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Arrow 2.0 release notes #312
Closed
Closed
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,180 @@ | ||
--- | ||
title: Arrow 2.0 release | ||
category: articles | ||
tags: [core, articles] | ||
--- | ||
|
||
# Arrow 2.0 release | ||
|
||
We are happy to announce the next major release of Arrow, version 2.0! | ||
As previously announced, migrating your projects to this release should be hassle-free | ||
if your code compiled in 1.2.x without any deprecation warnings | ||
(except for the breaking change in optics generation discussed below). | ||
|
||
This release is built with the new K2 compiler, and this gives us the ability | ||
to support a wider range of platforms, including WebAssembly. From now on, we shall | ||
provide artifacts for every platform supported by Kotlin. | ||
|
||
Apart from stabilization and general bug fixing, the theme of this release | ||
is improving the different DSLs provided by Arrow libraries. Our goal is to | ||
empower developers to write more succinct and readable code. | ||
|
||
* [Simple accumulation in Raise](#simple-accumulation-in-raise) | ||
* [Additions to Fx](#additions-to-fx) | ||
* [Clearer retries for particular exceptions](#clearer-retries-for-particular-exceptions) | ||
* [Improved optics](#improved-optics) | ||
* [Pattern matching](#pattern-matching) | ||
* [Better support for kotlinx.serialization](#better-support-for-kotlinxserialization) | ||
|
||
## Simple accumulation in Raise | ||
|
||
One of the core concepts when working with typed errors is the distinction | ||
between fail-first and accumulation of errors. Until now, the latter mode | ||
required using `parZip` and `parMap`, which sometimes obscure the actual | ||
flow of the computation. | ||
|
||
In Arrow 2.0 we have sprinkled some DSL dust over `Raise`, and now you can | ||
write your code in a more linear way. Inside an `accumulate` block (or in | ||
general, any `RaiseAccumulate`) you use `by accumulating` to execute some | ||
computation keeping all the errors. | ||
|
||
```kotlin | ||
// version with parZip | ||
parZip( | ||
{ checkOneThing() }, | ||
{ checkOtherThing() } | ||
) { a, b -> doSomething(a, b) } | ||
|
||
// version with accumulate | ||
accumulate { | ||
val a by accumulating { checkOneThing() } | ||
val b by accumulating { checkOtherThing() } | ||
doSomething(a, b) | ||
} | ||
``` | ||
|
||
This DSL also includes shortcuts for the most common operations, like | ||
`bind`ing and accumulating any problem, or checking a single property | ||
of some data. | ||
|
||
```kotlin | ||
accumulate { | ||
val name by Name(rawName).bindOrAccumulate() | ||
val age by ensureOrAccumulate(rawAge >= 18) { UnderAge } | ||
Person(name, age) | ||
} | ||
``` | ||
|
||
## Additions to Fx | ||
|
||
Writing coroutine-heavy code may become cumbersome over time, especially if | ||
one intends to use as much concurrency as possible. Arrow Fx includes a `parZip` | ||
function, but not everybody enjoys having so many brackets. | ||
|
||
```kotlin | ||
parZip( | ||
{ downloadFile() }, | ||
{ loadDataFromDatabase() } | ||
) { file, data -> Result(file, data) } | ||
``` | ||
|
||
The new `awaitAll` scope tries to improve the situation by tweaking the | ||
usual `async` mechanism, ensuring that all `Deferred` values are `await`ed | ||
once the first one is requested. That means that the previous code behaves | ||
identically to the following, that is, the call `file.await()` implicitly | ||
awaits every `async` defined up to that point. | ||
|
||
```kotlin | ||
awaitAll { | ||
val file = async { downloadFile() } | ||
val data = async { loadDataFromDatabase() } | ||
Result(file.await(), data.await()) | ||
} | ||
``` | ||
|
||
We've also improved the STM block by allowing delegation as a means to | ||
read or change the value of a `TVar`. | ||
|
||
```kotlin | ||
fun STM.deposit(accVar: TVar<Int>, amount: Int): Unit { | ||
val acc by accVar // delegation here | ||
val current = acc // implicit 'read' | ||
acc = current + amount // implicit 'write' | ||
} | ||
``` | ||
|
||
## Clearer retries for particular exceptions | ||
|
||
Until now, the `retry` operation in the Resilience module would capture | ||
any `Throwable` exception. From version 2.0 on you can specify a subclass | ||
of `Throwable` to be the target for retrying, whereas the rest of | ||
exceptions will bubble as usual. | ||
|
||
```kotlin | ||
Schedule.recurs<Throwable>(2) | ||
.retry<IllegalArgumentException, _> { ... } | ||
``` | ||
|
||
The subclass of exceptions must be given as a type argument. | ||
Alas, Kotlin does not allow giving only a subset of those, and `retry` | ||
has two type parameters (the second one represents the output type of | ||
the `Schedule`). Fortunately, you can ask the compiler to infer the | ||
second one using `_`. | ||
|
||
## Improved optics | ||
|
||
The two **breaking changes** in Arrow 2.0 relate to optics. | ||
First of all, the optics hierarchy has been greatly simplified: | ||
now we have traversals, optionals, lenses, prisms, and isos, and no more | ||
intermediate types. This smaller amount of types means that the type of | ||
optic compositions become easier to understand. | ||
|
||
We have also changed the generation of optics via the compiler plug-in | ||
(that is, the `@optics` annotation) with respect to nullable fields. | ||
In the 1.x series, a value of type `String?` would be presented as | ||
`Optional<T, String>`; this makes impossible to change the value from | ||
`null` to an actual `String` using only optics operations. From version | ||
2.0, that field is represented as `Lens<T, String?>`. To get the 1.x | ||
behavior you should apply `.notNull` after the optic corresponding to | ||
the field. | ||
|
||
One pain point when building traversals was the need to provide an | ||
argument to `.every`, like `.every(Every.list())`. This new version | ||
brings an improved variant that requires no arguments if the type | ||
of the `Iterable` is known. Similar improvements have been applied | ||
to `.at` and `.index`. | ||
|
||
## Pattern matching | ||
|
||
One completely new feature in Arrow 2.0 is the _pattern matching_ DSL. | ||
By combining prisms and lenses one can specify a complex shape, and | ||
then check whether a value fits into that shape, extracting some | ||
pieces of information on the go. The DSL gets quite close to pattern | ||
matching found in functional languages like Haskell or Scala. | ||
|
||
We do not intend this package to be a replacement for `when` expressions, | ||
smart casts, and guards already provided by the language. On the other | ||
hand, we acknowledge that pattern matching offers advantages when the | ||
code needs to inspect very nested data. | ||
|
||
```kotlin | ||
val User.name: String get() = this.matchOrThrow { | ||
// Company(name = nm, director = Name(lastName = d)) | ||
User.company(Company.name, Company.director(Name.lastName)) then { (nm, d) -> "$nm, att. $d" } | ||
// Person(Name(firstName = fn), age if it < 18) | ||
User.person(Person.name(Name.firstName), Person.age.suchThat { it < 18 }) then { (fn, _) -> fn } | ||
// Person(Name(firstName = fn, lastName = ln)) -> "Sir/Madam $fn $ln" | ||
User.person(Person.name(Name.firstName, Name.lastName)) then { (fn, ln) -> "Sir/Madam $fn $ln" } | ||
} | ||
``` | ||
|
||
We also provide a new package, `arrow-match`, which provides the same | ||
pattern matching DSL, but using Kotlin's reflection instead of optics. | ||
|
||
## Better support for kotlinx.serialization | ||
|
||
Using Arrow Core data types as part of serialized data requires additional integration. | ||
In 1.2.x we started providing compile-time support for `kotlinx.serialization`. | ||
From 2.0 on we also provide `ArrowModule` for | ||
[contextual serialization](https://github.com/Kotlin/kotlinx.serialization/blob/master/docs/serializers.md#contextual-serialization). This is needed, among others, when the data is processed | ||
by Ktor. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See other comment, I think it is important we can call
doWhile
onIllegalArgumentException
here as well.