-
Notifications
You must be signed in to change notification settings - Fork 310
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
Usage and meaning of Tap extension method #242
Comments
It doesn't change the result. The method you are referencing is an async version of the following method (the async version calls that method using
Here, this combination of
That's because the subsequent |
Yes, my example is not so clear, I've created tests to explain better:
I expect that both of these test will succeed, but the second fails, result is changed from success to failure |
Ah, I see what you mean. There should be equality members (including |
Let me add my 5 cents here. We use it rather wide like that: var result = _service.Get(id).ToResult(Error.NotFound) // Result<T>
.Tap(t => ValidatePermissions(user, t)) // ValidatePermissions: User -> T -> Result<Unit, Error>
.Tap(ValidateSomethingElse) // ValidateSomethingElse: T -> Result<Unit, Error>
.Tap(ThrottleRequests); // ThrottleRequests: T -> Result<Unit, Error>
result // Result<T, Error> Where both |
@vkhorikov sorry, may be I was not clear enough again. I mean such situation:
There are two methods, one returns void and the second returns result.
there are two variants of DoSomeJob method to make code compile:
This method
will look same in both situations, but in the 1-st case the result (failure or success) do depend on This looks confusing, because the @hankovich I'm agree that this is powerful and handy, but maybe we need another name for it? |
@mingazhev ah I see your point, Name is confusing indeed :) Several days ago I was discussing |
@mingazhev @hankovich looks like I didn't understand I think /cc @space-alien |
@hankovich Could you please post your implementation of |
@vkhorikov @mingazhev @hankovich How about naming it |
@hankovich If so, then why even use |
Originally these methods were called Please have a look at #181 where these methods were originally added, and also the discussion around naming here: #189 (comment) |
How about renaming to |
|
@vkhorikov we use very straightforward one public sealed class Unit
{
public static Unit Instance { get; } = new Unit();
} |
@Raibo let me add some details here public Result<Metadata, Error> Upload(File file, Guid token)
{
var tokenInfoResult = _authorizationManager.ValidateToken(token) // Returns Result<TokenInfo, Error> where TokenInfo contains some metainformation about the token while Error can contain ErrorType (NotFound/Forbidden/Validation/Throttling/etc) with additional details
.Tap(_ => _fileValidator.ValidateFile(file)) // ValidateFile returns Result<Unit, Error>
.Tap(_ => _throttleManager.TryStart(token)); // TryStart returns Result<Unit, Error>
// do your stuff with tokenInfoResult
} As you can see we use Tap as a filter for our results. We can not use Bind instead of Tap because we want our chain to return Another C# feature that we use frequently is local functions. So Does it make sense to you? |
@hankovich looks useful, we use something like this:
but I like your naming more |
I like @mingazhev please go ahead with the PR. Please make sure the APIs are backward compatible (i.e the old methods need to be marked as obsolete; there are some examples of that in the code base). |
@vkhorikov I'm ready with the changes but cannot push my branch (403) |
@mingazhev I think you should create a fork first, commit/push your changes and open a PR then. |
@vkhorikov @hankovich @mingazhev "Check" sounds like method with no side effect. But what if I have a method that returns Result<Unit, Error> and it has side effects. For example I want to call external service or update something in database but I want to keep initial input as output for that operation. For example language-ext uses linq query language so you can create nested selection
|
Do
This is more readable than LINQ queries, IMO. |
They return Result. You don't check for failure in your example. In that case you need to add at least two more rows for each check.
|
@nike61 It's up to you how to implement it, right? Nobody stops you from introducing side effects from any method (for example your Which name do you suggest? |
I mean "Tap" or "Func" or "Bind" don't sound like I can't change anything using them. But "Check" sounds like no side effect. |
I think I'm with @hankovich on this one. Side effect (or not) in the external method is not within the control of this library. |
I'm agree with @nike61 that in some cases Keeping method's name as @space-alien @hankovich @vkhorikov what do you think? Something meaningful for such operation. |
@nike61 If you have a better name, let's discuss, we can rename @mingazhev I don't quite like |
I think all done there, no new ideas |
Hey all, not sure if its still relevant, but what if we do this: Based on the examples from @mingazhev : #242 (comment) This would be 'Tap' [Fact]
public void Succeeding_test()
{
var successResult = Result.Success("ok");
Assert.True(successResult.Then(s => DoSomeJob()).IsSuccess);
static void DoSomeJob()
{
}
} This would be any of the following names:
I have not decided on a name that suits it best, personally, I like These would expect to execute a method that does not return [Fact]
public void Failing_test()
{
var successResult = Result.Success("ok");
Assert.True(successResult.Tap(s => DoSomeJob()).IsSuccess);
static Result DoSomeJob() => Result.Failure("error");
} I propose to implement a method with the I prefer Disregard the above ^^I did not realize the code was updated - I left the above text and did not erase it for context ProposalI propose that Reasons for change:I see that these changes have been made:
ProposalPersonally - I feel as if Check *CheckIf
This is not a binary expression of True Or False, its similar - but not. It is, however its so much more than that. It can execute a series of actions. And actions result in true or false, yes, but actions are not validations. Actions are executions. The word A Check is a binary result, not an execution While, |
I'm not quite sure if I understand |
We're using CSharpFunctionalExtensions package in our projects more than a year and we appreciated the changes of many
OnSuccess
methods to separate methods with different meaning, such asTap
,Bind
etc.After some using our team got an intuitive understanding of when to use each of them and we wrote not totally functional, but easy-readable and clear constructions such as:
When I read these lines I know that
GetAvailability
returns aResult<T1>
, then passes it to theConvertCurrencies
, which returns result of another type (Result<T2>
) and so on. When I see a usage ofTap
it looks like a method that doing nothing with returning result, just doing some job with no result (or having result as a Task). And as I understand, Tap has the same meaning in other languages.But during one of the code reviews we've found out that there are some
Tap
overloads that do change the returning result and this was totally surprising:Could you tell why it was done in such way and what is the new meaning of the
Tap
in terms of the library?The text was updated successfully, but these errors were encountered: