Open-NET-Libraries / Open.ChannelExtensions

A set of extensions for optimizing/simplifying System.Threading.Channels usage.
https://open-net-libraries.github.io/Open.ChannelExtensions/api/Open.ChannelExtensions.Extensions.html#methods
MIT License
401 stars 25 forks source link

Ambiguous ReadAllConcurrentlyAsync signatures, when using named arguments #13

Closed dittodhole closed 3 years ago

dittodhole commented 3 years ago

Hi there,

please consider following snippet:

channel.ReadAllConcurrentlyAsync(maxConcurency: ?,
                                 receiver: ?,
                                 cancellationToken: ?)

This call will fail with CS0121.

Referenced methods:

Additionally, TaskReadAllConcurrentlyAsync is also affected.

electricessence commented 3 years ago

I see. For the case where optional params are normalized, this begins to fail. I'm torn here. As you will always need to specify a max concurrency and a delegate. They are not optional. Only the cancellation token is optional.

The reason for theirs structure as they are is to simplify the code at use. Example:

reader.ReadAllConcurrentlyAsync(3, token, async e => {
});

instead of...

reader.ReadAllConcurrentlyAsync(3, async e => {
}, token);

Where the former has the execution as the last param/statement.

I thought about this quite a bit when making library, and started with the foundation of (maxConcurrency, receiver, cancellationToken = default) but found myself using the other signature more often for readability.

I'm open to suggestions. I have a few not so great ideas in my head, but altering the current API would likely break things. Thoughts?

dittodhole commented 3 years ago

Hm, I see ... thanks for the historical background!

Having an optional CancellationToken parameter as the last parameter is the signature I am used to from other enterprise projects (see Quartz.NET extending to async, see Polly with their ExecuteAsync signatures, ...), and I find that doing myself quite often (as it follows the "default" signature style). Additionally, the transform delegate could also share the CancellationToken.

Anyway, "2 methods doing the same thing" justify a breaking change imho (and might not be that big deal following SemVer)

electricessence commented 3 years ago

Yes. Normally I would follow the convention. But this only breaks when you are doing something very specific. Anyways,.. Hope this lib is helpful to you.

dittodhole commented 3 years ago

Just shared my thoughts (as requested), and acknowledge your point (no offense intended). The library is of tremendous help, just wanted to point out some (minor!, and from my modest experience) unusual design decisions.

electricessence commented 3 years ago

Appreciate it. I did struggle to make the puzzle work, and maybe in hindsight I might have come up with a way to retain the standard. But I can tell you, all the FxCop suggestions were there, I just decided on the most common use case for a fluent API.