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/use ArgumentException.ThrowIfNullOrEmpty #64357

Merged
merged 1 commit into from
Jan 28, 2022

Conversation

stephentoub
Copy link
Member

Adds ArgumentException.ThrowIfNullOrEmpty and then uses it in a bunch of places around the tree. Most of the replaced places used a resource string for the message, and I used it in places where it didn't feel like we were losing any meaningful information by centralizing on the single shared string, but I didn't use it in places where the resource string message used in the empty case conveyed something that seemed useful, e.g. a recommendation on what to use instead of an empty string.

There are a few places where I allowed for order of exception throws to change in the case where there were multiple user errors and the validation for a single argument was split, e.g. I changed a few cases of:

if (arg1 is null) throw new ArgumentNullException(...);
if (arg2 is null) throw new ArgumentNullException(...);
if (arg1.Length == 0) throw new ArgumentException(...);
if (arg2.Length == 0) throw new ArgumentException(...);

to:

ArgumentException.ThrowIfNullOrEmpty(arg1);
ArgumentException.ThrowIfNullOrEmpty(arg2);

even though it'll produce a different exception for M("", null) than it would previously. Technically a breaking change, but given this is a case of multiple usage errors and all the exceptions are ArgumentException-based, I think it's acceptable.

I wanted to get this in before we do the massive !! conversion, as I expect !! auto-fixes will make it a bit harder to roll this out. I explicitly did not do anything to roll out use of ArgumentNullException.ThrowIfNull, except in cases where I was modifying a method to use ArgumentException.ThrowIfNullOrEmpty, in which case for consistency I changed anything else in the function that could have been using ThrowIfNull to do so.

Fixes #62628

@stephentoub stephentoub added this to the 7.0.0 milestone Jan 26, 2022
@dotnet-issue-labeler dotnet-issue-labeler bot removed this from the 7.0.0 milestone Jan 26, 2022
@dotnet-issue-labeler
Copy link

Note regarding the new-api-needs-documentation label:

This serves as a reminder for when your PR is modifying a ref *.cs file and adding/modifying public APIs, to please make sure the API implementation in the src *.cs file is documented with triple slash comments, so the PR reviewers can sign off that change.

@ghost
Copy link

ghost commented Jan 26, 2022

Tagging subscribers to this area: @dotnet/area-meta
See info in area-owners.md if you want to be subscribed.

Issue Details

Adds ArgumentException.ThrowIfNullOrEmpty and then uses it in a bunch of places around the tree. Most of the replaced places used a resource string for the message, and I used it in places where it didn't feel like we were losing any meaningful information by centralizing on the single shared string, but I didn't use it in places where the resource string message used in the empty case conveyed something that seemed useful, e.g. a recommendation on what to use instead of an empty string.

There are a few places where I allowed for order of exception throws to change in the case where there were multiple user errors and the validation for a single argument was split, e.g. I changed a few cases of:

if (arg1 is null) throw new ArgumentNullException(...);
if (arg2 is null) throw new ArgumentNullException(...);
if (arg1.Length == 0) throw new ArgumentException(...);
if (arg2.Length == 0) throw new ArgumentException(...);

to:

ArgumentException.ThrowIfNullOrEmpty(arg1);
ArgumentException.ThrowIfNullOrEmpty(arg2);

even though it'll produce a different exception for M("", null) than it would previously. Technically a breaking change, but given this is a case of multiple usage errors and all the exceptions are ArgumentException-based, I think it's acceptable.

I wanted to get this in before we do the massive !! conversion, as I expect !! auto-fixes will make it a bit harder to roll this out. I explicitly did not do anything to roll out use of ArgumentNullException.ThrowIfNull, except in cases where I was modifying a method to use ArgumentException.ThrowIfNullOrEmpty, in which case for consistency I changed anything else in the function that could have been using ThrowIfNull to do so.

Fixes #62628

Author: stephentoub
Assignees: stephentoub
Labels:

area-Meta, new-api-needs-documentation

Milestone: -

@ghost
Copy link

ghost commented Jan 26, 2022

Tagging subscribers to this area: @dotnet/area-system-runtime
See info in area-owners.md if you want to be subscribed.

Issue Details

Adds ArgumentException.ThrowIfNullOrEmpty and then uses it in a bunch of places around the tree. Most of the replaced places used a resource string for the message, and I used it in places where it didn't feel like we were losing any meaningful information by centralizing on the single shared string, but I didn't use it in places where the resource string message used in the empty case conveyed something that seemed useful, e.g. a recommendation on what to use instead of an empty string.

There are a few places where I allowed for order of exception throws to change in the case where there were multiple user errors and the validation for a single argument was split, e.g. I changed a few cases of:

if (arg1 is null) throw new ArgumentNullException(...);
if (arg2 is null) throw new ArgumentNullException(...);
if (arg1.Length == 0) throw new ArgumentException(...);
if (arg2.Length == 0) throw new ArgumentException(...);

to:

ArgumentException.ThrowIfNullOrEmpty(arg1);
ArgumentException.ThrowIfNullOrEmpty(arg2);

even though it'll produce a different exception for M("", null) than it would previously. Technically a breaking change, but given this is a case of multiple usage errors and all the exceptions are ArgumentException-based, I think it's acceptable.

I wanted to get this in before we do the massive !! conversion, as I expect !! auto-fixes will make it a bit harder to roll this out. I explicitly did not do anything to roll out use of ArgumentNullException.ThrowIfNull, except in cases where I was modifying a method to use ArgumentException.ThrowIfNullOrEmpty, in which case for consistency I changed anything else in the function that could have been using ThrowIfNull to do so.

Fixes #62628

Author: stephentoub
Assignees: stephentoub
Labels:

area-System.Runtime, new-api-needs-documentation

Milestone: -

@danmoseley
Copy link
Member

Occurs to me reading this that eg ArgumentNullException.ThrowIfAnyNull(object, object) and ..(object, object, object) overloads would be fairly useful too.

@stephentoub
Copy link
Member Author

Occurs to me reading this that eg ArgumentNullException.ThrowIfAnyNull(object, object) and ..(object, object, object) overloads would be fairly useful too.

!! is going to handle the 99.99% case. I don't think we need to add any additional APIs for that.

Copy link
Member

@bartonjs bartonjs left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, modulo the compile errors.

@stephentoub
Copy link
Member Author

LGTM, modulo the compile errors.

Thanks, yeah, looks like I need to put back a resource or two I'd removed.

Copy link
Member

@adamsitnik adamsitnik left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Technically a breaking change, but given this is a case of multiple usage errors and all the exceptions are ArgumentException-based, I think it's acceptable.

I wholeheartedly agree. 👍

These changes look so good that I am surprised that we haven't come up with this idea sooner. Kudos to @datvm for the proposal!

@stephentoub stephentoub force-pushed the nulloremptyexception branch 2 times, most recently from d7d3ae0 to 80c975c Compare January 28, 2022 03:14
@carlreid
Copy link

We were just thinking a ThrowIfNullOrWhitespace would be nice on ArgumentNullException and just found this PR. Would this be the correct PR to also include ThrowIfNullOrWhitespace on? 🤔

That would align with String.IsNullOrWhiteSpace / String.IsNullOrEmpty checks

Adds ArgumentException.ThrowIfNullOrEmpty and then uses it in a bunch of places around the tree.  Most of the replaced places used a resource string for the message, and I used it in places where it didn't feel like we were losing any meaningful information by centralizing on the single shared string, but I didn't use it in places where the resource string message used in the empty case conveyed something that seemed useful, e.g. a recommendation on what to use instead of an empty string.

There are a few places where I allowed for order of exception throws to change in the case where there were multiple user errors and the validation for a single argument was split, e.g. I changed a few cases of:
    ```C#
        if (arg1 is null) throw new ArgumentNullException(...);
        if (arg2 is null) throw new ArgumentNullException(...);
        if (arg1.Length == 0) throw new ArgumentException(...);
        if (arg2.Length == 0) throw new ArgumentException(...);
    ```
to:
    ```C#
        ArgumentException.ThrowIfNullOrEmpty(arg1);
        ArgumentException.ThrowIfNullOrEmpty(arg2);
    ```
even though it'll produce a different exception for `M("", null)` than it would previously.  Technically a breaking change, but given this is a case of multiple usage errors and all the exceptions are ArgumentException-based, I think it's acceptable.

I wanted to get this in before we do the massive !! conversion, as I expect !! auto-fixes will make it a bit harder to roll this out.  I explicitly did not do anything to roll out use of ArgumentNullException.ThrowIfNull, except in cases where I was modifying a method to use ArgumentException.ThrowIfNullOrEmpty, in which case for consistency I changed anything else in the function that could have been using ThrowIfNull to do so.
@stephentoub
Copy link
Member Author

Would this be the correct PR to also include ThrowIfNullOrWhitespace on? 🤔

No, this PR is about the approved ThrowIfNullOrEmpty API. APIs need to be reviewed and approved following https://github.com/dotnet/runtime/blob/main/docs/project/api-review-process.md before PRs for them are accepted. That process starts with someone opening an issue proposing the APIs in question; please feel free to do so.

@stephentoub stephentoub merged commit 91da4ac into dotnet:main Jan 28, 2022
@stephentoub stephentoub deleted the nulloremptyexception branch January 28, 2022 19:16
@EgorBo
Copy link
Member

EgorBo commented Feb 3, 2022

All Improvements on windows-arm64 are related dotnet/perf-autofiling-issues#3288

@EgorBo
Copy link
Member

EgorBo commented Feb 3, 2022

Improvements on ubuntu-arm64: dotnet/perf-autofiling-issues#3294

@stephentoub
Copy link
Member Author

@EgorBo, while I'd love to take credit for such improvements, I'm skeptical they're because of this... e.g. I don't think Int64.Parse touches anything that overlaps with this PR. Why do we think it's related?

@EgorBo
Copy link
Member

EgorBo commented Feb 3, 2022

@stephentoub this change significantly affected inliner's decisions, e.g. https://sharplab.io/#v2:C4LghgzgtgPgAgJgIwFgBQ64BYAEBZACgHsAjAKwFMBjYHIgShwF4A+HYACwCciB3HAHYV+AQS4BzAK5QKA4ADlJAGyUBRAB5UKAB2ABLIgIICwMogDNi9egG4gA

for this throw we have to emit a lot of codegen and 4 calls in total so inliner's model assigns big weights to throw operations and such methods are rarely inlined. Not after your change, I see you also touched NumberFormatInfo.cs

@stephentoub
Copy link
Member Author

for this throw we have to emit a lot of codegen and 4 calls in total so inliner's model assigns big weights to throw operations and such methods are rarely inlined. Not after your change, I see you also touched NumberFormatInfo.cs

Yes... but I don't think any of those changes are anywhere on these code paths, are they?

@EgorBo
Copy link
Member

EgorBo commented Feb 3, 2022

Range of commits 01fabd0...c7adf55 #64405 is also a candidate, but do any of the parsing functions use StringBuilder?

Also, I assume you know, but don't look at the graphs in the issue - they don't reflect most recent improvements sometimes like today

@ghost ghost locked as resolved and limited conversation to collaborators Mar 5, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[API Proposal]: ArgumentException.ThrowIfNullOrEmpty(string)
6 participants