Skip to content

Champion: Simplified parameter null validation code #2145

@jaredpar

Description

@jaredpar
Member
  • Proposal added
    Discussed in LDM
    Decision in LDM
    Finalized (rejected)
    Spec'ed

Specification: https://github.com/dotnet/csharplang/blob/main/proposals/param-nullchecking.md

In short though this allows for standard null validation on parameters to be simplified using a small annotation on parameters:

// Before
void Insert(string s) {
  if (s is null)
    throw new ArgumentNullException(nameof(s));

  ...
}

// After
void Insert(string s!!) {
  ...
}

LDM history:

Activity

Thaina

Thaina commented on Jan 15, 2019

@Thaina

Shouldn't this be string! ?

And also doesn't C# will always warning on nullable reference type from now on?

jaredpar

jaredpar commented on Jan 15, 2019

@jaredpar
MemberAuthor

@Thaina

Shouldn't this be string! ?

No. This feature is for runtime value checking only. It does not affect the type system in any way. Hence the syntax annotation is on the value identifier, not the type.

And also doesn't C# will always warning on nullable reference type from now on?

Nullable reference type checking is an opt-in feature. Also it is designed to warn on potential null references in the code base but it doesn't affect the execution semantics of it.

qrli

qrli commented on Jan 15, 2019

@qrli

Maybe over simple, though ๐Ÿ˜†
And it looks like a declaration rather than implementation

DavidArno

DavidArno commented on Jan 15, 2019

@DavidArno

Great to see this proposal has resurfaced, and has been championed. I think it an excellent idea but thought it had been lost amongst all the other work going on around NRTs. Thanks, @jaredpar. ๐Ÿ‘

Joe4evr

Joe4evr commented on Jan 15, 2019

@Joe4evr
Contributor

Shouldn't this be string! ?

No. This feature is for runtime value checking only. It does not affect the type system in any way. Hence the syntax annotation is on the value identifier, not the type.

You say that, but the original idea does put it on the type.

GeirGrusom

GeirGrusom commented on Jan 15, 2019

@GeirGrusom

It's the dammit operator placed on the argument. It makes sense that it is applied to the value rather than the type.

alrz

alrz commented on Jan 15, 2019

@alrz
Member

It makes sense that it is applied to the value rather than the type.

that logic works only for parameters not property setters (that's why we'd need to invent syntax like set!). to me, this is more of a very specific code generation problem (what if I just want to Assert?), IMO the functionality should be a part of method contracts, or alternatively, some special attribute (which could be extended to other validation logics as well).

Thaina

Thaina commented on Jan 15, 2019

@Thaina

@Joe4evr If I understand it right (from the jaredpar's comment after mine) this is actually newer feature unrelated to nullable reference type. It just a syntactic sugar to throw exception while nullable reference type is compile time warning

Logerfo

Logerfo commented on Jan 15, 2019

@Logerfo
Contributor

is this feature supposed to ship with 8.0 as well?

DavidArno

DavidArno commented on Jan 15, 2019

@DavidArno

@Logerfo, my money is on "unlikely, but not impossible". Seems a candidate for 8.1+ to me. But I could be wrong...

bbarry

bbarry commented on Jan 16, 2019

@bbarry
Contributor

In isolation I think this is great but I'd much rather see a more comprehensive contract annotation system with a potential way to expand it for pattern matching validations and potentially even arbitrary code validation as well as return value validations, even if those advancements don't come as part of a first version of this.

In short I worry that this:

ReadOnlySpan<char> Foo(string s!, int n) 
{
    ...
}

means something like this will never happen:

ReadOnlySpan<char> Foo(string s, int n)
    requires s != null // perhaps: requires s! 
    requires s.Length > 0
    requires n >= 0
    requires n < s.Length
    ensures value.Length > 0 
{
    ...
}
Joe4evr

Joe4evr commented on Jan 16, 2019

@Joe4evr
Contributor

If I understand it right (from the jaredpar's comment after mine) this is actually newer feature unrelated to nullable reference type.

You're not wrong in that this feature could be achieved without NRTs, but the initial idea of having the compiler generate null checks for parameters (which is an extremely common scenario) came up during discussions of the NRT design. (Or rather, that was the moment the LDT would take it seriously. Theoretically, we could've had a syntax for generated null-checks ages ago.)

And while it's true that the check is about the value and not the type, applying the ! to the type 1) makes it more symmetrical, and 2) would probably make a lot of edge cases moot. (Granted, the reverse index syntax shows how much they care about symmetry. ยฏ\_(ใƒ„)_/ยฏ)

self-assigned this
on Jan 16, 2019
added this to the 8.0 candidate milestone on Jan 16, 2019

784 remaining items

Thaina

Thaina commented on Apr 19, 2022

@Thaina

Poll please. I don't want noise makers which are like 1% in any community forcing language team to cancel features actual majority needs.

I don't think they was just cancel it, it just being removed from C#11 because it not ready yet. It might come back later, but not now

AraHaan

AraHaan commented on Apr 19, 2022

@AraHaan
Member

Honestly the only form of param null checking I can think of are:

  1. the current form
  2. using % at the end instead.
  3. using [NotNull] attribute which then implicitly gets executed (with compiler inserted code to do so on it's parameters) that then calls the ThrowIfNull() function for us (but expose the attribute as a keyword where the compiler can transform it to the attribute and insert the code to "run the attribute's code inside").
AraHaan

AraHaan commented on Apr 20, 2022

@AraHaan
Member

@jaredpar why not keep this open for further discussion into possibly having this refined for future C# versions instead of closing it so that way more ideas for refinement can flow in?

Also just thought of this option as well:

public class Example
{
    public void Something(string s1 not null, bool b1 not null);
}

Where the existing keywords could be used by the compiler to insert an ThrowIfNull() call for each param marked with not null from pattern matching (but reused for this feature).

CyrusNajmabadi

CyrusNajmabadi commented on Apr 20, 2022

@CyrusNajmabadi
Member

This is an issue, which tracked an actual championed proposa/implementation. For a discussion, there should be an actual github discussion for it (which could link to this for example).

kimsey0

kimsey0 commented on Apr 20, 2022

@kimsey0
CyrusNajmabadi

CyrusNajmabadi commented on Apr 20, 2022

@CyrusNajmabadi
Member
sungaila

sungaila commented on Apr 20, 2022

@sungaila

https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-04-13.md#parameter-null-checking

void M(string s) where s is not null;
This looks like a promising start for a full contracts feature, but not for a feature only doing null checking of parameters.

I love that idea! Microsoft Research had these .NET code contracts for testing 14 years ago. Having pre-/postconditions, invariants and parameter null checking with first class language and compiler support would be awesome.

This would be one of the biggest and best C# releases yet!

AraHaan

AraHaan commented on Apr 20, 2022

@AraHaan
Member

@AraHaan we considered that syntax but didn't like it. See the notes in: https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-04-13.md#parameter-null-checking

While the LDM members might not like it, the community might. Same for using contracts to check for nulls. I think having all 3 of them as an option but as an .editorconfig option to select their personal preference on what they want to be used for param null checking.

There are devs who would prefer these for null checking:

  • !! (the current syntax)
  • not null (reuse these pattern matching keywords so devs new to C# can get the general idea that the function will throw if they pass in null (the !! for dummies as some people say).
  • where s1, b1 is not null; for using contracts to check multiple parameters at one time without having to mark each one with !! but do the same thing.
    • perfect for functions that take in 8 ~ 16 parameters where adding !! can be exhausting depending on how many of such functions they have in their code.
    • also perfect for having minimal line changes in their code while also being able to use the new feature to enforce parameters are not null, but have the compiler generate the throw for them as well for each parameter in their contract (minimizes whitespace changes).
CyrusNajmabadi

CyrusNajmabadi commented on Apr 20, 2022

@CyrusNajmabadi
Member

While the LDM members might not like it, the community might. Same for using contracts to check for nulls. I think having all 3 of them as an option but as an .editorconfig option to select their personal preference on what they want to be used for param null checking.

We will not do that. We're not going to add multiple redundant syntaxes because there are lots of different opinions on what people personally prefer for each of these areas.

TahirAhmadov

TahirAhmadov commented on Jul 15, 2022

@TahirAhmadov

Is there an issue/discussion and/or a champion for !! in expressions?

HaloFour

HaloFour commented on Jul 15, 2022

@HaloFour
Contributor

@TahirAhmadov

Is there an issue/discussion and/or a champion for !! in expressions?

Discussion, yes: #6034
Champion, no.

julealgon

julealgon commented on May 23, 2024

@julealgon

@jaredpar Shouldn't this issue be removed from the Working Set milestone, and also be "Closed as Not Planned" instead of "Closed as Completed"?

Right now, it gives the impression that this is implemented and coming again in C# 13.

jaredpar

jaredpar commented on May 23, 2024

@jaredpar
MemberAuthor

@julealgon changed to not planned but generally we don't remove the milestones when closing.

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

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Relationships

None yet

    Development

    No branches or pull requests

      Participants

      @asbjornu@binki@bbarry@mindplay-dk@jhgbrt

      Issue actions

        Champion: Simplified parameter null validation code ยท Issue #2145 ยท dotnet/csharplang