I suggest you ...

Add non-nullable reference types in C#

Non-nullability checks have to be manually encoded hundreds of times in any large real-world project, and they are not compile-time-enforced. There are code contracts in .Net 4.0, but their usage is still very verbose, and only partly compile-time-enforced.

What I wish is a pendant to the null-lifting operator ?, for instance, !, so that one could write:
void MyMethod(string! s){ /* s cannot be null :) */}

Or, the way ReSharper does it:
void MyMethod([NotNull] string s){ /* s cannot be null :) */}

6,022 votes
Vote
Sign in
Check!
(thinking…)
Reset
or sign in with
  • facebook
  • google
    Password icon
    Signed in as (Sign out)
    You have left! (?) (thinking…)
    Marc Sigrist shared this idea  ·   ·  Flag idea as inappropriate…  ·  Admin →

    129 comments

    Sign in
    Check!
    (thinking…)
    Reset
    or sign in with
    • facebook
    • google
      Password icon
      Signed in as (Sign out)
      Submitting...
      • Daniel Babralace commented  ·   ·  Flag as inappropriate

        Microsoft really missed a great opportunity when they introduced structs. Like the company often does, it fixated on the mechanics off programming rather than the concepts. Form follows function, and Microsoft often forgets the function when it gets tunnel vision on the form.

        When Microsoft introduced structs, it added the ? syntax to mark structs as nullable since, being on the stack, structs couldn't be nullable without a new mechanism. And this is where Microsoft made two mistakes.

        First, the application developer should not care at all whether something is on the stack or on the heap. The compiler, or better yet just-in-time compiler, should decide which is more efficient and just make a reference point to one or another. Thus there should be no keyword struct.

        Second and even more importantly, Microsoft didn't have the foresight or the courage to make all references non-nullable unless explicitly opted in by the developer with the ? syntax. Yes, this would break backwards compatibility with existing source code, but it would have been worth it a million times over, especially since a simple app could easily restore backwards compatibility by appending ? to every reference to a non-atomic type. This would make migration to the new platform trivial.

        Imagine if the compiler enforced that no variable and no parameter could be null unless declared with ?. Compile-time enforcement of non-null contracts would elimate countless problems and the declarations would be completely non-intrusive and obvioius. Let's just admit the real problem. Most programmers don't even think about null until a bug occurs. When most programers write

        public String MyMethod (String p1, MyClass p2)

        almost 100% of the time they really mean that the method does not take and does not return any nulls.

        Let's say they did want to take nulls for p2, but not p1 and would not return nulls. See how much clearer the syntax is...

        public String MyMethod (String p1, MyClass? p2)

        And if they wanted to return nulls,

        public String? MyMethod (String p1, MyClass p2)

        Seeing String? as the return type would inform the caller that the method may return nulls and the programmer calling this method is more likely to actually think about the consequences of this.

        Microsoft should really expand ? to be used for all types and make all references without ? to be non-nullable. A simple tool could translate source code to add ? to all references for backwards compatibility, and developers could then remove the unneeded ? at their leisure.

      • Peter commented  ·   ·  Flag as inappropriate

        Maybe I'm oversimplifying things, but IMHO this could be done using an attribute to parameters:

        void MyMethod([NotNull] string myParam)
        {
        }

        If the Compiler sees thiis, it injects something like

        if (value == null)
        {
        throw new ArgumentNullException(nameof(value));
        }

        Or even less verbs, by using something like the (string! myParam) the other poster proposed below.

        And I also would like to see some simple null check. In C++ I can just werite
        if (myPointer)
        for null checks. In C# I always have to write
        if (myRef == null)

        That's the only thing I don't like about C#: It is very verbose and needs a lot of code for simple things. Just look at Swift and how much less code it requires to express the same thing compared to C#.

      • sjb commented  ·   ·  Flag as inappropriate

        I vote for it being a full-blown type. It would be a reference type, analogous to the fact that int? is a value type. So you would have nullable reference types and non-nullable reference types. Like this:

        class BlogEntry {... }
        public void Method( BlogEntry! r) { /* r != null is always true in the body */ }
        ...
        BlogEntry myR;
        ...
        BlogEntry! yourR = myR; // compile error, no implicit conversion from BlogEntry to BlogEntry!
        BlogEntry! yourR = (BlogEntry!)myR; // compiles, run-time exception thrown if myR is null
        ...
        myR = yourR; // compiles, implicit conversion from BlogEntry! to BlogEntry, no runtime exception.

        BlogEntry! hisR = new BlogEntry( ...) // compiles, hisR is definitely assigned
        BlogEntry! hisR = yourR; // compiles, hisR is assigned same non-null value as yourR

        BlogEntry! goodExample( BlogEntry! someR) {
        BlogEntry! hisR;
        if (x == 7) {
        hisR = new BlogEntry(...);
        } else {
        hisR = someR;
        }
        return hisR; // compiles, hisR is definitely assigned before use.
        }

        BlogEntry! badExample( BlogEntry! someR) {
        BlogEntry! hisR;
        if (x == 7) {
        hisR = someR;
        }
        return hisR; // compile error, hisR is not definitely assigned before use.
        }

        BlogEntry!? otherR; // compile error, BlogEntry! is not a value type (also not legal syntax).
        BlogEntry?! thirdR; // compile error, BlogEntry is not a value type (also not legal syntax)
        int?! xx; // compile error, int? is not a reference type (also not legal syntax)
        BlogEntry!! doubleR; // compile error, BlogEntry! is not a nullable reference type (also not legal syntax)

      Feedback and Knowledge Base