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

["Request"] Feedback to make Arrow more approachable #3303

Open
schielek opened this issue Nov 29, 2023 · 4 comments
Open

["Request"] Feedback to make Arrow more approachable #3303

schielek opened this issue Nov 29, 2023 · 4 comments

Comments

@schielek
Copy link

What version are you currently using?

1.2.0

What would you like to see?

What's great?

Arrow's raise DSL is a masterpiece of engineering. It has all the benefits of type-safe error handling without compromising green path programming and therefore fosters readability.

Concrete vs. Abstract

I love that function names in the raise DSL are very concrete. fun raise(r: Error): Nothing clearly indicates that we deal with error handling here. A person not familiar with Arrow or even Kotlin can understand what the code does. Either.Left on the other hand is abstract. It takes time to get used to the convention that Either.Left models errors and Either.Right models the green path, but I feel like it is an unnecessary price to pay if I use Either only for error handling. (For other cases I have sealed data types and would never long for Either.)

Suggestions for some Renaming/Aliases

getOrRaise instead of/along with bind

I propose to introduce getOrRaise as an alias for bind. It goes along with other functions such as getOrElse, getOrNull, and getOrNone.

either {
    // result is of type Either here
    result.getOrElse {  }
    result.getOrNull()
    result.getOrNone()
    result.bind() // abstract and unreadable
    result.getOrRaise() // does not exist :(
}

get and error instead of/along with left and right

As mentioned before left and right are rather abstract.

// result is of type Either here
// Right cases have 'get' functions indicating success/green path
result.getOrElse {  }
result.getOrNull()
result.getOrNone()

// Left cases only have 'left' functions. There isn't a readable alternative indicating errors
result.leftOrNull()
result.onLeft {  }
result.mapLeft {  }

// These would be better but do not exist
result.errorOrNull()
result.onError { }
result.mapError { }

parMap and parZip

This is not part of the raise DSL but belongs into a similar category since it affects readability. Some function names such as parMap and parZip are directly taken from Haskell. While it is apparent to Haskell developers what these functions do, it might not be for the average Kotlin developer.
I suggest going with the Kotlin/Java philosophy of avoiding abbreviations where possible.
parallelMap and parallelZip have five more characters but can save a lot of headache when reading code.

Note

This issue is rather meant as a feedback or an impulse for a discussion than a feature request. I would be happy if some people would join the conversation and leave their thoughts.

@serras
Copy link
Member

serras commented Nov 30, 2023

Hi @schielek, thanks for your feedback!

We usually try to strike a balance between Kotlin-idiomatic names and names coming from the functional programming sphere. Left is one of that examples: the name itself is very common in Haskell, Scala, and similar languages. It's not that we think it's perfect, but rather we try that every material out there that talks about functional error handling would be similarly applicable to Arrow.

Personally, I like some of your suggestions like getOrRaise, but I would not replace those functions, but rather provide both versions. That way we cover both camps: bind is a very recognizable name from somebody used to the "monadic lingo", whereas getOrRaise follows Kotlin idioms more closely.

@serras
Copy link
Member

serras commented Nov 30, 2023

On the other hand, I think that renaming parZip to parallelZip would not make such a difference, and we would be breaking source compatibility.

@schielek
Copy link
Author

schielek commented Dec 1, 2023

@serras
Thanks for your kind words, Alejandro.

  1. I agree that changing the semantics of or adding semantics to a popular construct like Left is a dangerous decision. While providing some value to the Kotlin-idiomatic faction it could mean a lot of anger for the Haskell/Scala faction.
  2. I appreciate that you consider getOrRaise a viable alias and Kotlin-idiomatic alternative to bind. Depending on what other community members think I would be very happy to see this in the future.
  3. I still think it does make a difference to rename parMap, but that could just be me. Kotlin provides decent tools for deprecation and the Kotlin team has shown the communities acceptance for those deprecation cycles e.g. in the stdlib.

@CLOVIS-AI
Copy link
Contributor

As user, I think getOrRaise is a great name—however I am worried that having two names for the same thing will force users to know both names to be able to read code, which makes it even harder. Unless one is clearly favored compared to the other (e.g. by deprecating one of them), I don't think having both will help readability.

With regards to Either.Left/Right, as I said on Slack, I don't think this is a big issue: with context receivers, almost the entire Arrow API is Raise-based, not Either-based. Since creating your own either-like datatype is just matter of implementing bind and the DSL constructor (trivial with fold), it becomes very simple to not use Either at all if a team finds it unclear.

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

No branches or pull requests

3 participants