News

Devs Sound Off on C# 11 Preview Features Like Parameter Null Checking

A sneak peek at upcoming C# 11 preview features drew some developer ire, especially on parameter null checking.

Microsoft this week posted an Early peek at C# 11 features that detailed preview constructs like list patterns, a tweak affecting newlines in interpolated strings, and parameter null checking.

The Feb. 22 post quickly led to an unusually large number of comments with many on the negative side and, within that group, many focused on the latter item, parameter null checking.

This preview feature proposal stems from C# 8's introduction of nullable reference types (NRT), which proved controversial in their own right.

C# Plans
[Click on image for larger view.] C# Plans (source: Microsoft).

The Parameter Null Checking proposal on GitHub says, "This proposal provides a simplified syntax for validating method arguments are not null and throwing ArgumentNullException appropriately."

The motivation behind the proposal reads: "The work on designing nullable reference types has caused us to examine the code necessary for null argument validation. Given that NRT doesn't affect code execution developers still must add if (arg is null) throw boiler plate code even in projects which are fully null clean. This gave us the desire to explore a minimal syntax for argument null validation in the language. While this null parameter validation syntax is expected to pair frequently with NRT, the proposal is fully independent of it. The syntax can be used independent of #nullable directives."

In effect, it simplifies the code needed by using what Microsoft calls the "bang-bang operator," or "!!."

Thus the old way of checking:

public static void Hello(string name)
{
    if (name is null)
    {
        throw new ArgumentNullException(nameof(name));
    }

    Console.WriteLine("Hello, " + name);
}

or the .NET 6 alternative:

public static void Hello(string name)
{
    ArgumentNullException.ThrowIfNull(name);
    Console.WriteLine("Hello, " + name);
}

can become simply:

public static void Hello(string name!!)
{
    // Body of the method
}

which is then turned into something like this via code generation:

void Hello(string name) {
    if (name is null) {
        throw new ArgumentNullException(nameof(name));
    }
    ...
}

"We are putting this feature into this early preview to ensure we have time to get feedback," said principal program manager Kathleen Dollard in yesterday's post. "There have been discussions on a very succinct syntax vs. a more verbose one. We want to get customer feedback and from users that have had a chance to experiment with this feature.

"Code will be generated to perform the null check. The generated null check will execute before any of the code within the method. For constructors, the null check occurs before field initialization, calls to base constructors, and calls to this constructors."

For such a seemingly innocuous preview feature, it generated several (unedited) negative comments along the lines of:

  • I don't like parameter null checking feature. It doesn't feels like a nice addition to the language and have already caused a lot of holywars. Why does you introduce a new syntax for this? Why you can't use existing notnull keyword on the type, not on the parameter name? Why do you use !! on the parameter name? It even contradicts with NRT feature, where strict null's validation can be added.
  • Putting the !! on the parameter rather than the type is fitting here since it's the value of the parameter that's being checked. Things that go with the type should only be there if they describe something about the type. There's no type anywhere else that can be string!! or string?!!. That said, it feels a bit ridiculous and out-of-place that a special two-punctuation-character incantation is introduced just to throw a certain exception.
  • I agree. The NRT project is a success so this feature is not needed. If any consuming project has NRT turned off then that is its problem.
  • I agree !! syntax is ugly as hell. It adds noise to the code, it is not self explanatory, and makes newcomers overwhelmed (like F#, that contains lots of syntax gotchas and has one of the most ugly syntax ever produced).
  • Why !! at all? If parameter is nullable, and there is no explicit check/branch for null in code, exception generation can be implied. Advanced mode can check that all calls for this private/internal member already have checked for null and skip it to reduce amount of checks.

There are more, but you get the idea.

One detailed post addressed just the code generation:

Auto-generating such code would be a very bad idea. Therefore this really isn't an option. I can think of several cases where auto-generating such code without prompting from the dev would not work well.
  • Some methods shouldn't throw an ANE on null but NRE. The use case here is an extension method as they should behave like instance members. Instance members do not throw ANE but NRE. But you should not throw an NRE yourself so the only way to get this to work properly is to reference the instance.
  • In many cases higher level methods already validate arguments and therefore lower level methods should not auto-check as well. This is wasteful and there is no way to know whether such a case exists or not given just a method declaration.
  • Accessibility doesn't matter in terms of "already checked". If you could even do such analysis (what if there are cases where the args are checked and others aren't) it still isn't reliable. For example a method, irrelevant of accessibility, can be passed as a delegate to other code. There is no way to do code analysis and detect this. Hence you'd have to come up with heuristics to determine when to enable/disable such a feature (e.g. accessibility) and that just makes it a lot harder to understand. It would also then be a breaking change to change the accessibility of a method (currently it generally isn't if you go from more restrictive to less).
  • Finally, it would be a breaking change to suddenly start throwing ANE in code that didn't previously. Somebody somewhere could be wrapping that code in typed exception handlers and would suddenly see different behavior.
Auto-generation of code without a programmer indicating they want it is almost always a bad idea. It must always be opt in.

You can find in the blog post many more comments and much more reasoning behind the proposed preview feature and the others mentioned above, which were publicized to garner developer feedback. Along with the comments section of her post, Dollard recommends the discussion area of the CSharpLang GitHub repo for providing such feedback.

Note that to try out the new features, you must use Visual Studio 17.1 and .NET SDK 6.0.200 and set LangVersion to preview.

What do you think of nullable parameter checks and other preview C# proposals? Share your thoughts in the comments below.

About the Author

David Ramel is an editor and writer at Converge 360.

comments powered by Disqus

Featured

  • Compare New GitHub Copilot Free Plan for Visual Studio/VS Code to Paid Plans

    The free plan restricts the number of completions, chat requests and access to AI models, being suitable for occasional users and small projects.

  • Diving Deep into .NET MAUI

    Ever since someone figured out that fiddling bits results in source code, developers have sought one codebase for all types of apps on all platforms, with Microsoft's latest attempt to further that effort being .NET MAUI.

  • Copilot AI Boosts Abound in New VS Code v1.96

    Microsoft improved on its new "Copilot Edit" functionality in the latest release of Visual Studio Code, v1.96, its open-source based code editor that has become the most popular in the world according to many surveys.

  • AdaBoost Regression Using C#

    Dr. James McCaffrey from Microsoft Research presents a complete end-to-end demonstration of the AdaBoost.R2 algorithm for regression problems (where the goal is to predict a single numeric value). The implementation follows the original source research paper closely, so you can use it as a guide for customization for specific scenarios.

  • Versioning and Documenting ASP.NET Core Services

    Building an API with ASP.NET Core is only half the job. If your API is going to live more than one release cycle, you're going to need to version it. If you have other people building clients for it, you're going to need to document it.

Subscribe on YouTube