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 :) */}

2,558 votes
Sign in
or sign in with
  • facebook
  • google
    Password icon
    I agree to the terms of service
    Signed in as (Sign out)
    You have left! (?) (thinking…)
    Marc SigristMarc Sigrist shared this idea  ·   ·  Flag idea as inappropriate…  ·  Admin →


    Sign in
    or sign in with
    • facebook
    • google
      Password icon
      I agree to the terms of service
      Signed in as (Sign out)
      • Steve LeighSteve Leigh commented  ·   ·  Flag as inappropriate

        @Philippe: I don't think anyone has said it should be mandatory. See https://github.com/dotnet/roslyn/issues/5032.

        Simply put, I can declare

        Foo? myFoo = new Foo();

        and be guaranteed at compile time that it's not nullable. I can still assign it to a nullable reference type (eg. pass it to DoSomething(Foo foo)), so we can keep all backwards compatibility.

      • PhilippePhilippe commented  ·   ·  Flag as inappropriate

        Another thing... Now that ?. operator has been added, it would give contrary views of the problem. On one hand we make it easier to write code that handle null and on the other hand, we want to avoid the possibility to have null references.

        Given the wide use of C#, if non null reference is added to the language, I think it should be optional as readonly and other modifiers.

        And also would it be possible to write generic code that works appropriately in both cases? It is already hard to write generic code because it is much less flexible than C++ templates.

        For example, for container that allows to specify an initial size including built-in arrays, what would be the initial value of each item? would default(T!) give a new T? If so the type must support default new. Existing container don't have such restriction and it is not possible to vary those clause depending on the type...

        Or would some member functions have additional restrictions. Maybe such fonctions should then be annotated to indicate that they are only available for type that can be default construct.

        Thus it might be preferable to support metaprogramming first in the language... but then would you want to go as far as C++?

      • PhilippePhilippe commented  ·   ·  Flag as inappropriate

        While it might be nice to add non-nullable reference, they should not be the default.

        One might argue that it would be the best default. Assuming it was a new language, then probably. At this point, it would be a major breaking change. So much code has been written with that assumption.

        It could be explicit using either ! notation or a NotNull attribute or some "required" modifier.

        Beyond the fact that it would break too much code, another reason why non null reference should not be the default, is for consistency with other features that do not have the best default according to the point of view of what would typically lead to the best design.

        If non null reference would be the default, then readonly, const and pure functions should also be the default...

        On the other hand, if non null reference support is added, then having an attribute (or modifier) that allows it the default on a per type basis might make sense.

        Also, such changes would have impact on generic code. How function like TryGetValue should works? I guess one would have to use a temporary nullable reference in that case and initialize a non null reference from it after ensuring it is not null.

        However, it is not possible to write a function similar to TryGetValue that would works on non nullable types. That is, it would returns false and the compiler would known that the variable should be used only when the function returns true. Thus extra attributes (or even some form of advanced conditionnal code contract) would be required...

      • Paulo ZemekPaulo Zemek commented  ·   ·  Flag as inappropriate

        Dax, actually you are misunderstanding how it is supposed to work.
        If you have a field that can't be null, it must be initialized or else the construction fails.
        Then, if you try to set null to it is supposed to fail, using reflection or anything else.
        So, there's no need to check for "unchecked" or anything else.
        And, considering .NET doesn't really have a not-null for reference types, it simply means that any method that uses the field, variable etc will start by checking if the value is different than null, throwing an exception if it is null (a different one than NullReferenceException... maybe the ArgumentNullException for input arguments)... yet, the compiler could help by disallowing, at compile-time, passing null constants or expressions known to return null.

      • Dax FohlDax Fohl commented  ·   ·  Flag as inappropriate

        I don't think this will ever work quite right. You'll parse something using JSON.NET and it'll be null even though it's supposedly not a valid value. This happens with F# records.

        So *then*, rather than just a null check, an "unchecked {if (*x == 0) {}}" check, which is even worse.

        The CLR has nulls, so there's always the chance that one will sneak in where it shouldn't. You'd simply need a different runtime, that doesn't support nulls at all, like Rust, to support this feature correctly.

      • PauloPaulo commented  ·   ·  Flag as inappropriate

        Dag, that struct is useless in C#.
        Anybody can declare a variable like:
        public readonly NotNull<string> ThisIsNeverInitialized;

        As the variable is not initialized, it will contain null.
        You can also initialize it using default(NotNull<string>); and when getting the value, it will be null.

        The problem is the fact that structs have a default!

      • Dag Øystein JohansenDag Øystein Johansen commented  ·   ·  Flag as inappropriate

        @paulo You can make a NotNull<T> struct and use it like you described the C++ case:

        public struct NotNull<T> where T: class
        public NonNull(T object)
        if (object == null)
        throw new ArgumentNullException();

        Value = object;

        public T Value { get; set; };

        // elsewhere...

        void foo(NotNull<string> s)
        DoSomething(s.Value.ToUpper()); // s.Value is guaranteed never to be null.

        What is missing here is the argument name. That can be quite important though, and I much prefer the far less typing-intensive analog to the System.Nullable<T> shorthand. The "string!" shorthand would make it as easy to modify existing code (that lacks the argument check) as adding the exclamation mark. The other approach is more cumbersome.

        That said, it seems to me that MS could elect to do this in a way quite similar to what they did with System.Nullable *and* get the parameter name too, since C# 5 has provisions for obtaining the names of parameters.

      • Dag Øystein JohansenDag Øystein Johansen commented  ·   ·  Flag as inappropriate

        What you're asking for isn't really "non-nullable reference types" but a way to specify to the compiler that method parameters cannot be null. The compiler can't, in general, check if arguments are null at compile-time (that would indeed require non-nullable reference types, which is a bad idea IMHO), but it could generate the argument-checking code we now have to write, and method signatures would have a bit more information than they do now.

        I would love to see

        void foo(string! arg1, MyClass! arg2)
        DoStuff(arg1, arg2);

        be equivalent to

        void foo(string arg1, MyClass arg2)
        if (arg1 == null)
        throw new ArgumentNullException("arg1");

        if (arg2 == null)
        throw new ArgumentNullException("arg2");

        DoStuff(arg1, arg2);

        Good code should usually catch exceptions in *very* few places, make use of try-finally blocks for things like preventing leaks (without catching), and throw exceptions in LOTS of places (though it shouldn't happen often at runtime of course). Checking arguments for nulls is of course only one of many situations where code should check things and throw easy-to-understand exceptions in case assumptions are violated (also, the check-and-throw code *documents* what assumptions the developer made), but I think it's obvious from the code sample above why it would be helpful to have something like this.

      • PauloPaulo commented  ·   ·  Flag as inappropriate

        Marian, a struct in C# can always be default initialized, which actually kills the purpose in most cases.
        In C++ it is possible to use a non-pointer class without a default constructor to be the "not null reference"... a class like NotNull<T>. So, in its constructor, it receives a T * but validates it is not null.
        In C# the problem is that a struct can always be default initialized (big mistake, in my opinion) and a reference is, by default, null supporting.

        Notice that the default initialization for value-types and null initialization for references only happens for class fields. Local variables must be initialized in C#, or else you receive a compile time error because you try to use a non-initialized variable. As well, struct fields must be initialized on its constructor... the only problem is the existence of the "automatic default" for structs... which also happens to be valid only when they are used inside classes.

      • Marián ŠpánikMarián Špánik commented  ·   ·  Flag as inappropriate

        One possible solution is to use a structs instead of classes. The struct, as a value type, can't be null. However the struct can't be polymorphic (at least I think so) and you can't store any reference to it anywhere and you have to not forget to pass it as a reference to every function (ref keyword), otherwise you would copy it in each call. Also existing classes can't be used as the structs...

      • PhylosPhylos commented  ·   ·  Flag as inappropriate

        Perhaps those wanting non-nullable reference types are asking too much from the C# type system. This would be such a fundamental change to C# that one wonders if it's even possible without breaking some fundamental aspects of the type system.

        F# was able to have non-nullable reference types because it was a fundamental part its' type system from the outset, not something bolted on years after the language had been released.

      • Anonymous commented  ·   ·  Flag as inappropriate

        i think we need some giant red buttons labeled

        [help i dont know what im doing]
        [im super lazy auto program for me]

      • Anonymous commented  ·   ·  Flag as inappropriate

        this is so absolutely stupid to me
        i don't understand why this is even needed or for what it is needed

        why not a property guess what... its auto initialized... that's what properties do... try it yourself ....

        to boot this suggestion borders the most fundamental harasy
        the idea of non strict types and no type safety
        whats next [non strict] C1 c;

        hey check it out... how about this ?
        public class A
        string Value{get;set;}

        how do you even say this [NotNull] string value in a parameter
        what if you need to pass null to the value ? you what to change the language because of your particular constructor

        so the compiler has to check parameters for non null so then other people can complain about even slower compiles because were so lazy

        class C2 {
        public C2(string value) { if (value == null) throw new ArgumentNullException("value");
        for(int i = 0; i < 1000; i++) new C1(value);}
        "This clearly shows how strongly reduced performance because of the presence of such verifications"

        are you kidding ? for(int i = 0; i < 1000; i++) new C1(value);}
        first who puts this in there constructor for absolutely no reason

        second you want a [non null] keyword that magically writes this basically
        { if (value == null) throw new ArgumentNullException("value");
        your saying that somehow by magic it will be more performant if the compiler or jit adds the code to infer the check dynamically instead of you typing in that line in your very specific constructor really ?

        my real question
        is were is any real example of any need for this or
        anyone that actually needs this because
        they couldn't simply use a property instead ?

      • MSMS commented  ·   ·  Flag as inappropriate

        Why not a simple and sweet keyword

        void MyMethod(notnull string s)

      • AsadAsad commented  ·   ·  Flag as inappropriate

        @MauricioScheffer You're misunderstanding the point of non-nullable types if you think option types are an alternative to them. Option types are the necessary complement to non-nullable types, and are used to represent something that may or may not have a value. They're only useful if you can safely assume anything other than an option type will *not* be null.

        In this suggestion, normal reference types are going to be acting as option types, in that we may or may not get a value of the specified type. Adding a bang, however, allows you to specify as part of the compile time contract that you are accepting/returning a non nullable type, which is the logical complement of our default nullable/option types.

      ← Previous 1 3 4

      Feedback and Knowledge Base