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

Validated conditionally #2603

Closed
wants to merge 6 commits into from
Closed

Conversation

abendt
Copy link
Contributor

@abendt abendt commented Dec 20, 2021

this adds Validated.conditionally and conditionallyNel (#2570)

Comment on lines +113 to +114
public inline fun <L, R> conditionally(test: Boolean, ifFalse: () -> L, ifTrue: () -> R): Validated<L, R> =
if (test) Valid(ifTrue()) else Invalid(ifFalse())
Copy link
Member

Choose a reason for hiding this comment

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

Seeing this version for Validated makes me wondering if it's more clear or obscuring the code.
All snippets below are equivalent, since Arrow is considered to have a high learning curve think we should be weary of the API surface in Arrow.

val guard = false

val a = Validated(guard, { "succeed" }) { "fail" }
val b = if(guard) Valid("succeed") else Invalid("fail") 

val c = Either.conditionally(guard, { "succeed" }) { "fail" }
val d = if(guard) "succeed".right() else Invalid("fail").left()
val e = either<String, String> {
  ensure(guard) { "fail" )
  "succeed"
}

Copy link
Member

Choose a reason for hiding this comment

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

I've sometimes used this, and I think it gains when you write it like this:

val c = Either.conditionally(
  guard,
  ifFalse = { "fail " },
  ifTrue = { "succeed" }
)

Given that similar function is available in Scala, my feeling is that this may actually help users.

Copy link
Member

Choose a reason for hiding this comment

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

What should be our decision here, @nomisRev? I am happy with approval.

Copy link
Member

Choose a reason for hiding this comment

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

I am also in favor of less obscure code, one can still bridge to Validated via toValidated, bc then we probably need to do the same for Option and other Bifunctors.
But this involves a further look into Arrow, which API's add obscure code paths in general.

Copy link
Member

Choose a reason for hiding this comment

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

@abendt I think these functions are fine but they increase the API surface which is something we want to trim going forward.

if (test) Valid(ifTrue()) else Invalid(ifFalse())

vs

Validated.conditionally(test, ifFalse(), ifTrue())

We were in favor of these kinds of idioms in the past but since we decided to complement the kotlin std lib and the lang, we prefer to use the lang control flow mechanism where they are expression-based as in the case of if. An exception for this is Either.catch because control of exceptions and the semantics with suspending are harder for users to encode.

Happy with this going forward since this PR has already two approvals.
Going forward I think we should look into trimming down all data types APIs where possible.

IMO most data types like Either can get away with just fold and bind and the rest are largely irrelevant because of bind and the either block. Even more irrelevant in the future in the case of multiple context receivers where we can constraint functions to the EffectScope<E> and just shift without using Either then interpret to Either or Validated. For example as shown in #2661

class DomainError(msg: String) 

context(CoroutineScope, EffectScope<DomainError>)
suspend fun program(): Int {
    val fa = async<Int> { shift(DomainError("error")) }
    val fb = async { delay(2000); 1 }
    return fa.await() + fb.await()
}

Copy link
Member

Choose a reason for hiding this comment

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

Happy with this going forward since this PR has already two approvals.

I actually removed my approval (sorry @abendt), since we have a lot of issues with the API surface of Arrow.
I think if (test) Valid(ifTrue()) else Invalid(ifFalse()) reads better than Validated.conditionally(test, ifFalse(), ifTrue()) since everyone understands the first one, but the same isn't true for the second one. So this actually increases the learning curve of Arrow, which definitely is a bad thing. This kind of idioms exists in languages/effect systems that use final tagless and express ifM, conditionally through tagless implementations.

Therefore I'm actually in favor of deprecation Either.conditionally instead of addding Validated.conditionally as I argued in another comment above too.

What do you think @abendt?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

fair enough @nomisRev and @raulraja
i can fully understand the reasoning to simplify the API surface, makes sense for maintainability and as you mentioned for the learning curve.

my main motivation for the PR was to write and contribute some code. So i am not too attached to the actual functionality, so i fully support your decision.

my only suggestion would be to cleanup the existing github issues so its easier to find the ones you want support on.

Copy link
Member

Choose a reason for hiding this comment

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

Thank you for your understanding and support of Arrow @abendt. We should really make a better effort in maintaining the Github issues but it's very difficult and time-consuming. Shameful to admit it's been on my TODO list for 2+ years to clean up and add beginner tickets :/

@serras serras self-requested a review December 24, 2021 10:35
Copy link
Member

@nomisRev nomisRev left a comment

Choose a reason for hiding this comment

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

Sorry for the long wait @abendt. This got lost among my notifications.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants