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

Add andTee() implementation #445

Open
untidy-hair opened this issue Jan 17, 2023 · 3 comments · May be fixed by #467
Open

Add andTee() implementation #445

untidy-hair opened this issue Jan 17, 2023 · 3 comments · May be fixed by #467

Comments

@untidy-hair
Copy link
Contributor

untidy-hair commented Jan 17, 2023

Hi @supermacro and all the contributors, I love neverthrow, thank you for this great library!

In the ideal functional world, we don't want side-effects but in reality, we do need to handle side effects. When we do so, it is usually a good idea to separate pure functions from side effect functions cleanly. And in some of those cases, you want to use the result of the previous computation after you call a side effect function. Of course we can do so with the current API, too, but it would be sleek if we have something like andTee() which we would be able to use as follows:

// validate returns ResultAsync
validate(userInfoInput).andThen(buildUser).andTee(persistUser).andThen(notifyUserRegistration)....

or perhaps for logging

// doSomeEventProcess returns ResultAsync
doSomeEventProcess(input).andTee(logEvent).andThen(doNextThing)....

The potential signature would be:

// On ResultAsync
andTee<F>(f: (t: T) => ResultAsync<unknown, F>): ResultAsync<T, E | F> 
// Typically unknown above is void
// In case of failure, it passes along the error F instead.

// On Result (asyncAndTee)
asyncAndTee<F>(f: (t: T) => ResultAsync<unknown, F>): ResultAsync<T, E | F> 

There might be better naming than "tee".

I found this library just about a month ago so hopefully I'm not missing anything.
I will be happy to make a PR if this idea sounds a good addition :)

[Edit]
I was looking at tests and got inspiration after seeing asyncMap and updated the contents above.

@mheinzerling
Copy link

Currently I'm running the snippet below. A tee would be nice.

.map(ok => {
  doSomething();
  return ok;
})
.mapErr(err => {
  doSomething();
  return err;
});

The persistUser seems to be a strange use case, but logging or a stopwatch (as in my case) might benefit from handling ok and error cases in one function without changing the result type. I'm not even sure if the new tee-methods should allow a different error type. I guess they should be "readonly" and just not fail.

@untidy-hair
Copy link
Contributor Author

I see, so there can be two version of tees, one which allows passing errors to downstream and the other which does not care about the error. persistUser is what exactly I need. (and I'm going to rewrite our codebase with andTee once it is adopted.) I have implemented this so I might go ahead and make a PR.

@untidy-hair
Copy link
Contributor Author

untidy-hair commented Apr 3, 2023

Hi @mheinzerling, I made a PR as I said, and I implemented andTee() 'readonly' as you said considering the meaning of the tee :) In cases like mine where you want to stop the main logic flow upon a side-effect logic failure, I also added andThrough() altho I'm not sure if that's the best name.

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 a pull request may close this issue.

2 participants