Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Introduce Tap #21

Open
raphaelimahorn opened this issue Jul 13, 2021 · 2 comments
Open

Introduce Tap #21

raphaelimahorn opened this issue Jul 13, 2021 · 2 comments
Milestone

Comments

@raphaelimahorn
Copy link
Contributor

When chaining Result's, there is often the need to work with the results value more than once, e.g. for logging and inform some listeners. One can use the functions Map and AndThen to do that, however, we than have to return the input again, which often requires to use heavier code, while with a Tap often a simple method group could be used.

With Tap one could write

result
    .Tap(Console.Write)
    .Tap(Publish);

Without the same functionality looks something like this:

result.
    .Map(ok =>
   {
        Console.Write(ok);
        return ok;
   }).Map(Publish);

The proposed naming is inspired by tap from rxjs and can be argued because of it's simmilarity to map.

As for Map and AndThen also a TapAsync as well as TapErr and TapErrAsync should be introduced.

@phkiener
Copy link
Collaborator

phkiener commented Aug 1, 2021

Instead of introducing a whoe batch of new methods (Tap, TapAsync, TapErr, TapErrAsync, ...), I strongly believe in function composition. The side-effects like logging are often actions as in returning void instead of a value - which is impossible to compose. Depending on your exact code, you should easily get away with a private helper to handle the "execute the action and return the given value". If that's not the case, a more generic Do higher-order function can work for you.. something like

public static T Do<T>(Action<T> action)
{
    return x => {
        action.Invoke(x);
        return x;
    };
}

I still am unsure whether we'd want stuff like this in Galaxus.Functional - there're many similar nice helpers, but they don't flow that well in actual production code I think.

@SamuelBittmann
Copy link

While we didn't call it Tap(...) (we followed the naming suggestion from Scott Wlaschin), we used to have a very similar extension method in our code to handle this. Since then the code calling the extension method changed and we no longer need this extension anymore, but as Scott states in his talk, Railway oriented programming (https://fsharpforfunandprofit.com/rop/), handing over a value to a method returning void is a quite common need. How about we add Tap(...), Tee(...), or whatever we want to call it, directly to the types and move all separate concerns (e.g. async) to their own project, as suggested here: #25?

@phkiener phkiener added this to the 5.0.0 milestone Jan 28, 2023
# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Development

No branches or pull requests

3 participants