Skip to content
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 #2778

Merged
merged 190 commits into from
Apr 24, 2024
Merged

Arrow 2.0 #2778

merged 190 commits into from
Apr 24, 2024

Conversation

serras
Copy link
Member

@serras serras commented Jul 29, 2022

This is a PR to track breaking changes to be included in Arrow 2.0.

Proposing new changes

If you would like to propose a feature or change for inclusion in Arrow 2.0, you can either:

  • Open a PR against the arrow-2 branch,
  • Create an issue tagged with "Arrow 2.0".

One of our goals is to make Arrow simpler to use, so you should expect some amount of discussion for new or breaking APIs.

Breaking changes

Migration

  • Migration script for changing imports for breaking APIs if the signatures are compatible

Exploration

  • Review API to see what we can skim of the public API
    • Either#replicate, Either#find, etc.
  • Explore making Effect<E, A> a typealias for suspend Shift<E>.() -> A[Arrow 2.0] Effect without suspending shift #2797
    • Rename Shift to Raise (or CanFail) based on user feedback
    • Add recover API for Option & Ior and catch for Result.

PRs closed without merging

gradle.properties Outdated Show resolved Hide resolved
@lenguyenthanh
Copy link
Contributor

lenguyenthanh commented Jul 30, 2022

Should we set the minimum version of Kotlin for v2.0, so we know which features we can includes to v2.0. I believe should mostly include stable kotlin features.

@kyay10
Copy link
Collaborator

kyay10 commented Jul 30, 2022

Draft PR for Boxing-free Option type: #2780. That PR is for Arrow 1.x though because it includes Deprecated functions and functions for Validated and Effect etc, so I'll make another PR against Arrow 2.0.

@nomisRev
Copy link
Member

@lenguyenthanh that is a great suggestion!
I’m sure we’d all love to use newer features, but we need to prefer stability for downstream libraries and projects. It’s important for long term success.

We should probably prefer releasing major versions in the future to adopt new language features such as context receivers, or sealed value classes.

I suspect development of Arrow 2.0 will take quite some time, so 1.7.x or maybe 1.8.x could be a good candidate. Or should libraries prefer older versions? Is there any documentation oriented for library authors that you know of?

@nomisRev
Copy link
Member

@kyay10 thanks for taking the time for making the PRs, and doing the investigation 🙏

@serras
Copy link
Member Author

serras commented Jul 30, 2022

@lenguyenthanh @nomisRev I would suggest targeting the 1.7 series of the compiler, so we can make use of the new context receivers. As you point out, maybe when we release Arrow 2.0 an ever newer version would have come out, so I think that’s a safe bet.

@Atternatt
Copy link
Collaborator

@nomisRev @serras I asked the Kotlin channel for an estimation of the official release of context receivers. They estimate the release in Kotlin 1.9

@Atternatt
Copy link
Collaborator

would it make sense create streamable object like Kotlin flows but with Either or Validated behaviors and operators? (perhaps it's a stupid question)

@codependent
Copy link

I'd like to bring up the possibility of offering a high level class like Scala's ZIO to model an effectful program. What do you think about it? Does it make sense in the context of Arrow?

@nomisRev
Copy link
Member

nomisRev commented Aug 1, 2022

Hey @codependent, thanks for the suggestion. Is there any reason or use-cases that you would prefer a ZIO data type over what currently is possible in Kotlin with Effect + suspend + Kotlin/Arrow Fx Coroutines ?

I don't think a class like ZIO makes sense in Kotlin (unrelated to Arrow) because the philosophy of Kotlin is to build independent features that should conveniently compose together, and therefore there is no need to implement concrete classes to combine different concerns. I.e. KotlinX Coroutines takes the same approach with Structured Concurrency and its API.

For example the equivalent of ZIO#parZip.

object Error

fun one(): Effect<Error, Int> = effect { 
  delay(100)
  1
}

effect<E, A> {
   parZip(
     { one().bind() },
     { one().bind() }
   ) { x, y -> x + y }
}.fold({ fail("Never results in Error") }, { println(it) }) // 2

We can easily nest parZip inside effect, and effectively "mix" their abilities. Afaik ZIO offers their model because it aims to provide a simpler model to monad transformers, an issue which we don't have here.

When Kotlin releases context receivers, you can also drop the Effect return type completely as well (including other wrappers in the return type). Resulting in clearer code and more Kotlin idiomatic code, with very little APIs you need to learn.
This model also covers all use-cases that ZIO covers, and solves all issues that ZIO aims to solve.

@codependent
Copy link

When Kotlin releases context receivers, you can also drop the Effect return type completely as well (including other wrappers in the return type). Resulting in clearer code and more Kotlin idiomatic code, with very little APIs you need to learn. This model also covers all use-cases that ZIO covers, and solves all issues that ZIO aims to solve.

@nomisRev I was suggesting it since the only aspect that bugged me (just a little bit) is that Arrow offers different monads (Either, Validated, Option...), that usually are present in the return types of the business services, forcing us to convert (transform) them from one to another in our logic definition. ZIO's approach differs in which it aims to provide a One-Monad-For-All and define the program logic just based on it.

I misunderstood the introduction of the Effect runtime as way to move to an Arrow "super monad", but as you kindly explained that wasn't necessarily the case.

In any case, as you pointed out, context receivers will definitely make our Kotlin code more idiomatic and clearer and Arrow isn't really missing anything feature-wise compared to ZIO. Thanks for your explanation.

@nomisRev
Copy link
Member

nomisRev commented Aug 1, 2022

@codependent maybe as a clarification on the StackOverflow answer (and let me know if you think I should update my answer accordingly).

I misunderstood the introduction of the Effect runtime as way to move to an Arrow "super monad"

Effect offers a way to move to a "super monad", as it's the most abstract implementation. However, Arrow doesn't force you to use Effect.

We suspect there are many people in the Kotlin community that would rather work with suspend fun myFunction(): Either<MyError, A> rather than:

context(EffectScope<E>)
suspend fun myFunction(): A

Given that both are isomorphic to each-other there is no strong technical argument to which is better.

the only aspect that bugged me (just a little bit) is that Arrow offers different monads (Either, Validated, Option...), that usually are present in the return types of the business services, forcing us to convert (transform) them from one to another in our logic definition.

With Arrow 2.0 we want to streamline this more. Reducing the API surface, and optimising for the context(EffectScope<E>) case since the Either users will also benefit from that. Hence also the tasks to remove Validated, and other redundant data types for Arrow 2.0. As a way of unifying duplicated use-cases between different data types. This should improve your frustration with the different monads. So I am looking forward to your feedback when we're making such changes. If you're interested I can tag you in relevant PRs (If I don't forget 🙈).

@codependent
Copy link

@nomisRev I’ll be glad to have a look at those changes. Apart from those small details, Arrow is a fantastic library that improved noticeably with each version, congrats for the awesome work 👍

@nomisRev nomisRev added the 2.0.0 Tickets / PRs belonging to Arrow 2.0 label Aug 3, 2022
nomisRev and others added 14 commits August 4, 2022 09:03
* Flatten Resource ADT, maintain API
* Shift without suspend, inline all the rest
* Add new error handlers signatures
* Make ShiftCancellationException private
* Remove all references to shift from new code

* Update API files
* Add Resource.allocated() to decompose Resource into it's allocate and… (#2820)
* [2743] Migrate internal use of CircuitBreaker double to duration (#2748)
* Fix typo (#2824)
* Make the server disconnect test more general (#2822)
* Update NonEmptyList.fromList deprecation to suggest `toOption()` instead (#2832)
* Improve Either.getOrHandle() docs (#2833)
* Improve allocated, and fix knit examples
Co-authored-by: Jeff Martin <[email protected]>
Co-authored-by: Martin Moore <[email protected]>
Co-authored-by: valery1707 <[email protected]>
Co-authored-by: Lukasz Kalnik <[email protected]>
Co-authored-by: stylianosgakis <[email protected]>
* Two small deprecations

* Add Atomic module, and StateShift. Implement ior through StateShift

* Fix build

* Fix atomic knit

* Fix knit attempt #2

* Update API files

* Remove references to shift
@nomisRev
Copy link
Member

Here it goes @serras @kyay10. If everything blows up.. just point at me :D

@nomisRev nomisRev marked this pull request as ready for review April 24, 2024 10:38
uses: gradle/gradle-build-action@v2
with:
arguments: check
arguments: jvmTest
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you experience problems with the build again @serras ?

@@ -50,8 +50,12 @@ class NonEmptyListTest {

@Test
fun iterableToNonEmptyListOrNullShouldWorkCorrectlyWhenTheIterableStartsWithOrContainsNull() = runTest {
checkAll(Arb.nonEmptyList(Arb.int().orNull())) { nonEmptyList ->
nonEmptyList.all.toNonEmptyListOrNull().shouldNotBeNull() shouldBe nonEmptyList
checkAll(Arb.list(Arb.int())) { list ->
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@serras this was my fix, d5b188c. It's super weird this started failing..

I would not go for this fix, this has a nested checkAll so this runs 1000x1000=100_000? 🤔

cc\ @kyay10

@nomisRev nomisRev merged commit 2613059 into main Apr 24, 2024
12 of 13 checks passed
@hugomd hugomd mentioned this pull request May 21, 2024
6 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
2.0.0 Tickets / PRs belonging to Arrow 2.0
Projects
None yet
Development

Successfully merging this pull request may close these issues.