Skip to content

Consider adding default for CancellationToken parameters in interfaces / classes in 4.0.0 #376

Closed

Description

@brental

It is a common pattern for interface and class methods with CancellationToken parameters to specify a default for the parameter so that it can be called without the parameter by consumers. This includes interface and class methods with CancellationToken parameters in various Microsoft libraries such as (but not limited to) the dotnet runtime and AspNetCore as well as in other libraries. For consistency with this established pattern, consider adding this to the interface and class methods where CancellationToken parameters were added in the 4.0.0 preview.

As an example:
IAsyncEnumerable GetFeatureNamesAsync(CancellationToken cancellationToken = default);

Activity

  1. changed the title [-]Consider adding default for CancellationToken parameters in new interfaces / classes in 4.0.0[/-] [+]Consider adding default for CancellationToken parameters in interfaces / classes in 4.0.0[/+] on Feb 23, 2024
  2. zhenlan commented on Mar 9, 2024

    @zhenlan
    Member

    Agreed. This is an oversight. Thanks brental.

    Zhiyuan Liang (@zhiyuanliang-ms) Ross Grambo (@rossgrambo) can one you take this on. Please check all interfaces/types applicable.

  3. zhiyuanliang-ms commented on Mar 10, 2024

    @zhiyuanliang-ms
    Member

    Zhenlan Wang (@zhenlan) Jimmy, Ross and I had a discussion about this issue. I just shared the teams chat history to you.

  4. zhiyuanliang-ms commented on Mar 10, 2024

    @zhiyuanliang-ms
    Member

    Zhenlan Wang (@zhenlan) brental
    Not providing default value for cancellationToken is by design. Here is the discussion of this API: #250 (comment)

    Last month, when we saw brental opened this issue, we had another discussion about it.

    We agree that it will make the caller code look simpler if there is a default value for cancellation token.

    But, omitting cancellation token on async method invocation is not a good practice. Caller should be explicit that it does't intend to be canceled. It is terrible to accidentally omit the propagation of cancellation.

    If .NET has established the paradigm, we should not go against the it. So we did some investigation about how common the default value pattern is.

    Cancellation token with default value is not common in the Azure .NET SDK.
    : https://github.com/search?q=repo%3AAzure%2Fazure-sdk-for-net+%22%2C+CancellationToken+token%22&type=code

    System.IO lib provides default value for cancellation token: https://learn.microsoft.com/en-us/dotnet/api/system.io.stream.readasync?view=net-8.0&source=docs

    System.Net.Http doesn't provide default value for cancellation token: https://learn.microsoft.com/en-us/dotnet/api/system.net.http.httpclient.postasync?view=net-8.0#system-net-http-httpclient-postasync(system-string-system-net-http-httpcontent-system-threading-cancellationtoken)

    System.Data.Entity doesn't provide default value for cancellation token: https://learn.microsoft.com/en-us/dotnet/api/system.data.entity.queryableextensions.anyasync?view=entity-framework-6.2.0#system-data-entity-queryableextensions-anyasync-1(system-linq-iqueryable((-0))-system-threading-cancellationtoken)

    According to our investigation, it seems like there is no such paradigm. So we decided to keep the current design.

    This is a code snippet from System.Net.Http:
    image
    You can see that there are two APIs: 1. PostAsync(String, HttpContent, CancellationToken) and 2. PostAsync(String, HttpContent)

    PostAsync(String, HttpContent, CancellationToken) will be called by PostAsync(String, HttpContent) and CancellationToken.None will be used.

    This is how we implemented FeatureManager.IsEnabledAsync:
    image

    image

    Maybe, we can update it to

    public async Task<bool> IsEnabledAsync(string feature)
    {
        return await IsEnabledAsync(feature, CancellationToken.None);
    }
  5. brental commented on Mar 10, 2024

    @brental
    ContributorAuthor

    The point about the caller being explicit that it doesn't want to be cancelled does makes sense.

    However, the investigation done into whether the default is being used in .NET seems like it has missed a lot cases where it is used.

    For example the search in the Azure SDK links to the following search:
    https://github.com/search?q=repo%3AAzure%2Fazure-sdk-for-net+%22%2C+CancellationToken+token%22&type=code

    That search omits cases where the Cancellationtoken parameter is named cancellationToken rather than token and potentially cases where the token is the first parameter. These searches show more cases of using default:
    https://github.com/search?q=repo%3AAzure%2Fazure-sdk-for-net+%22cancellationToken+token+%3D+default%22&type=code

    https://github.com/search?q=repo%3AAzure%2Fazure-sdk-for-net+%22cancellationToken+cancellationtoken+%3D+default%22&type=code

    These searches do show cases where default is not being used:
    https://github.com/search?q=repo%3AAzure%2Fazure-sdk-for-net+%22cancellationToken+token%2C%22&type=code

    https://github.com/search?q=repo%3AAzure%2Fazure-sdk-for-net+%22cancellationToken+token%29%22&type=code

    https://github.com/search?q=repo%3AAzure%2Fazure-sdk-for-net+%22cancellationToken+cancellationtoken%29%22&type=code

    https://github.com/search?q=repo%3AAzure%2Fazure-sdk-for-net+%22cancellationToken+cancellationtoken%2C%22&type=code

    So, there is definitely a mix of it being used and not being used, but seems like there are more cases where it is being used in the Azure SDK.

    However, doing similar searches in the dotnet runtime and aspnetcore repos does show a mix as well, but in those two repos it is the opposite and there are more cases without the default then with.

    So, given that there is a mix of default and no default it seems like the point about the caller being explicit that it doesn't want to be cancelled probably gives a good enough reason not to have the default. Consumers who do want that overload could always implement extension methods without the parameter if they really wanted it.

    However, I would also point out that looking at the comparison of the System.Net.Http methods and the FeatureManager.IsEnabledAsync methods it seems like the point was that they are equivalent. However, the two FeatureManager.IsEnabledAsync methods shown do not accept a Cancellation token at all where as the System.Net.Http methods do. So, I am not sure what that comparison was meant to highlight? It seems like the two FeatureManager.IsEnabledAsync should have a CancellationToken parameter though. Is it going to be added to those as well?

  6. zhiyuanliang-ms commented on Mar 10, 2024

    @zhiyuanliang-ms
    Member

    brental Thank you for your continued interest and support for this repo. Appreciate you taking the time to do the investigation.

    That search omits cases where the Cancellationtoken parameter is named cancellationToken rather than token and potentially cases where the token is the first parameter.

    Sorry, I was wrong.

    So, there is definitely a mix of it being used and not being used, but seems like there are more cases where it is being used in the Azure SDK.

    Then, it makes the option to provide default value more appealing.

    However, I would also point out that looking at the comparison of the System.Net.Http methods and the FeatureManager.IsEnabledAsync methods it seems like the point was that they are equivalent. However, the two FeatureManager.IsEnabledAsync methods shown do not accept a Cancellation token at all where as the System.Net.Http methods do. So, I am not sure what that comparison was meant to highlight? It seems like the two FeatureManager.IsEnabledAsync should have a CancellationToken parameter though. Is it going to be added to those as well?

    I've updated my comment. Sorry for the unclearness.

  7. brental commented on Mar 10, 2024

    @brental
    ContributorAuthor

    No worries Zhiyuan Liang (@zhiyuanliang-ms).

    Then, it makes the option to provide default value more appealing.

    My initial thoughts were that the majority of the code in the dotnet runtime and aspnetcore libraries had the default for CancellationToken parameters. Those searches I did earlier show that is not the case. They also show that the Azure SDK has more usages of default but it is still a mix of using the default and not using the default. So, I would be happy if you end up sticking with the decision not to use the default it in this library. The reasoning for not using it (the caller being explicit) makes sense to me.

    It sounds like there might still be a discussion required with Zhenlan Wang (@zhenlan) but I can close this issue without any changes if the outcome is that default will not be used.

    There is still the issue of Feature manager methods not having Cancellation token parameters, but a separate issue could be raised for that.

  8. zhenlan commented on Mar 10, 2024

    @zhenlan
    Member

    It's good practice to make CancellationToken required for nonpublic APIs. It ensures the proper propagation of the CancellationToken between method calls. But for public APIs, IMO, we should give people an option.

  9. jimmyca15 commented on Mar 11, 2024

    @jimmyca15
    Member

    Zhiyuan Liang (@zhiyuanliang-ms) wasn't the outcome of any previous discussion on this that .NET IO classes included default cancellation so it would reasonable for us to do the same?

  10. zhiyuanliang-ms commented on Mar 12, 2024

    @zhiyuanliang-ms
    Member

    Jimmy Campbell (@jimmyca15) Sorry for the misunderstanding. PR #395 sent out.

  11. zhiyuanliang-ms commented on Mar 22, 2024

    @zhiyuanliang-ms
    Member

    #395 has been merged.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions