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

1,581 votes
Vote
Sign in
Check!
(thinking…)
Reset
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 →

    47 comments

    Sign in
    Check!
    (thinking…)
    Reset
    or sign in with
    • facebook
    • google
      Password icon
      I agree to the terms of service
      Signed in as (Sign out)
      Submitting...
      • Pavel Evgenjevich TimoshenkoPavel Evgenjevich Timoshenko commented  ·   ·  Flag as inappropriate

        I propose to consider the following example

        class C1 { public C1(string value) { if (value == null) ... } ...}
        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. We could achieve performance benefits due to the fact that the C# has JIT compiler. Consider the following code modification:

        class C1 { public C1([NotNull] string value) { ... } ...}
        class C2 { public C2([NotNull] string value) {
        for(int i = 0; i < 1000; i++) new C1(value); ...}...}

        When compiling attributes are bypassed with code optimization allowing to reduce the number of verifications. I agree with the opinion was expressed that the use of attributes slightly reduces code readability. For this role might be suitable exclamation mark symbol. However, if you look at the scope of attributes, in fact in this case they are more suitable.

        Anyway attributes in C# is very mysterious. On the one hand they are used for storing metadata. On the other hand they miraculous way can do a lot. I for clear language, free from any kind of synthetic hacks. Why in this case does not allow legal use of some useful features of the PostSharp? For example could be given the opportunity to influence the attributes of the compilation process. Made available without any the possibility of realizing hacks validations applied to a piece of code that attribute. Also interesting is the ability to perform actions not only at compile time, but at run time.

        In conclusion, I would like to support the idea of ​​using attributes for partial implementation of code contracts that can be verifiable and optimizable during compilation process. In addition attributes can be customizable:

        [NotNull(exception=typeof(ArgumentNullException)),
        Length(1, 255, message=Properties.Resources.ErrorMessage)] String someValue;

        NotNull:CodeContractAttribute, Length:CodeContractAttribute

      • Johann DirryJohann Dirry commented  ·   ·  Flag as inappropriate

        I believe that it makes lot sense to implement this, because it allows for compiler checking, rather than relying on throwing exceptions. It should work similar to Code Contract's Requires-statement.

        -----------------------
        Method 1 (default):

        void MyMethod(string s)
        {
            if(s == null)
            {
                throw new ArgumentNullException("s");
            }
        // do something...
        }

        Pro:
        * every developer knows it.
        * straighforward to implement

        Con:
        * code will be repeated everywhere
        * checking is in called function, not in calling function

        -----------------------
        Method 2 (bad!):

        If you want it to check only while development, you can use Debug.Assert.

        void MyMethod(string s)
        {
            Debug.Assert(s != null, "Parameter 's' must not be null.");
        // do something...
        }

        Pro:
        * every developer knows it
        * runs a bit faster because no checking in production code

        Con:
        * Code will be repeated
        * Dependency on System.Diagnostics, NUnit, or similar
        * will not check production code

        -----------------------
        Method 3 (perfect):

        Use [Code Contracts].

        void MyMethod(string s)
        {
            Contract.Requires<ArgumentNullException>(s != null, "s");
        // do something...
        }

        Pro:
        * caller must ensure that variable is not null, rather than called method
        * static checking (even before compiling)
        * may be written in a way that minimizes code duplication
        * developer can decide if checking should be done in production code or not using compiler flags

        Con:
        * vew developers understand it
        * implementing static checks are time consuming
        * dependency on CodeContracts when used in production code
        * still a research project, so there is no commitment for its adaptation to new C#/.NET versions.

        -----------------------
        Method 4 (very good):

        Use [PostSharp] ().

        void MyMethod([NotNull] string s)
        {
        // do something...
        }

        Pro:
        * exactly what you want
        * eliminates code duplication
        * you can change what the aspect does by implementing your own
        * no dependencies

        Con:
        * Commercial tool (but usually worth the money)

        [Code Contracts] http://research.microsoft.com/en-us/projects/contracts/
        [PostSharp] http://www.postsharp.net/blog/post/Validating-parameters-field-and-properties-in-PostSharp-3

      • PauloPaulo commented  ·   ·  Flag as inappropriate

        I must say that I see a lot of people saying that we can't have a NonNullable<string> type.
        And I agree. But doing a string! doesn't need to be a real type, only an automatic validation. It can even be a synctatic sugar for a [NotNull]string, which is used by the compiler to do the:
        if (s == null)
        throw new ArgumentNullException("s");

        It will really eliminate lots of duplicated code, will reduce the number of errors caused by people who refactor the parameter names but forget the exception message and things like that.

        In fact, I created a "required" for parameters in POLAR:
        http://www.codeproject.com/Articles/280361/POLAR-Creating-a-Virtual-Machine-in-NET

        So I can guarantee that it works.

      • Martijn HoekstraMartijn Hoekstra commented  ·   ·  Flag as inappropriate

        @Vladislav don't mistake a program with undefined behavior with being not well-formed. It explicitly is allowed in the language specification with undefined behaviour, nothing non-well-formed about it (but a bad idea nonetheless)

      • Anonymous commented  ·   ·  Flag as inappropriate

        @Paulo: Actually, your example is not correct: dereferencing null pointer in C++ is undefined behaviour, the program is not well-formed.

      • Paulo SequeiraPaulo Sequeira commented  ·   ·  Flag as inappropriate

        @Vladislav, in C++ it's still possible to have the compiler accept null assignments to references:

        C* pC = null;
        C& rC = &pC;

        So, there's still a runtime component to guaranteeing non-nullability.

        That is not to say non-null type declarations are not useful: they take away from the programmer most of the burden of writing null checks (the compiler would generate the checks for you), and you would only have to deal with it explicitly in the boundaries where converting to/from nullable.

        The syntax would also help reducing risk of causing null pointer exceptions, and would also allow for easing flow analysis so that the compiler could remove the null checks when it can be sure they're not needed.

      • Joel GreijerJoel Greijer commented  ·   ·  Flag as inappropriate

        Wow this would be really great. I've written so much unneccessary code to check for null in strings and classes. And many of those crazy unneccessary nullref-exceptions would be lost

      • gzakgzak commented  ·   ·  Flag as inappropriate

        @Vladislav

        "With the non-nullable strings, the first case (you are sure that string is not null) will be explicitly expressed by the former string having static type string! instead... so you'll just need to propagate the new type, switching from implicit logical condition in your program (some variables here and there may not be null) to explicit ones"

        Exactly.
        But I would argue that this is actually a fairly expensive propagation.
        Consider:

        void Foo(string s) { MyMethod(A(s) + B(s) + C(s) + s); }

        Where A, B, and C all accept and return plain string values, not string! values. Does this compile? If so, all the null-checks are runtime checks. If it doesn't compile, how do you fix it? And imagine if you don't own A, B, and C. Now what?

        The thing is, you have to start with the notion of non-nullable types and grow from there. But if you've already grown a large code base without them, it's impractical to introduce them later. That's what's missing here...

      • Anonymous commented  ·   ·  Flag as inappropriate

        @gzak: well, I won't point to the Spec# language which is able to enforce nun-nullable semantics, I'll point to a well-known example: C++. The C++'s references are basically the same as non-nullable references. So if C++ is able to cope with such a feature, why C# cannot be?

        Next, consider your example of MyMethod accepting string!. This has an equivalent right now, without non-nullable string: the documentation for the method may say that the string argument must be non-null. As a good citizen, you must either be sure that the string which you have is non-null, or you must check it before passing as argument. (You have a 3rd option of forgetting to check and getting a weird runtime exception though.)

        With the non-nullable strings, the first case (you are sure that string is not null) will be explicitly expressed by the former string having static type string! instead. The second case with runtime check will be unchanged: now you need it not for satisfying the requirement, but for converting string into a string!. (The third case is however not possible, which is a clear advantage.)

        Note that each string literal is itself a string!, so you'll just need to propagate the new type, switching from implicit logical condition in your program (some variables here and there may not be null) to explicit ones. The operations on strings and system functions known to return a non-null string can be automatically un-lifted by the compiler.

        Next, about solving the problem with division. Basically you are right in noticing that problem of invalid operations may be solved with a more strict type system. However introducing a non-zero int seems for me too big change for too small gain, and that is the only reason it's not suggested elsewhere.

        P.S.: I've already given my vote for safe navigation operator.

      • gzakgzak commented  ·   ·  Flag as inappropriate

        Fundamentally, you can't enforce this kind of thing entirely at compile time in the same way you can't entirely catch division-by-zero errors at compile time (at least, not pleasantly).

        An important thing to notice here is that while it looks like you've solved the nullability problem for MyMethod, you've actually just pushed it up to all of its callers.

        Suppose a caller has a regular string, not a string!, can they pass it to MyMethod? If so, that's automatically a runtime check.

        Or do they in turn also need a string! first? But now the caller has to change. And god forbid the caller's string in turn came from one of its arguments, or from the result of some other method call, suddenly it becomes exponentially difficult for the caller of MyMethod to secure a string! to pass in... That would be the only way to 100% enforce this at compile time.

        And if there's a "converter" from string to string!, that converter is again a runtime check, automatically.

        Basically, to enforce this entirely at compile time you'd need to exponentially ripple the string! change all the way up the various call stacks (and sometimes down some other branches). It would be similar with trying to catch division-by-zero, where you can imagine something like this:

        int MyDivider(int y, int~ x) { /* int~ means non-zero int, so x cannot be 0 */ }

        So while I very much like the idea of non-nullability in theory, in practice it wouldn't really work, especially without breaking compatibility with a ton of existing code. It would really only work if you were designing a language from scratch, one which only has value types. But C# isn't that language, if you'd like that you should use F# instead.

        That's why I'm more in favor of introducing a ?. operator. It's comparatively simple, and doesn't break anything. Less is more...

        http://visualstudio.uservoice.com/forums/121579-visual-studio/suggestions/3990187-add-operator-to-c-

      • JimmyJimmy commented  ·   ·  Flag as inappropriate

        then you have (string.IsNullOrEmpty(myString) ? "It's null, shoot!" : "Its not null, YES!");

        or (myString.Equals(null) ? "It's null, shoot!" : "Its not null, YES!");

        sorry just putting my 2 cents in...

      • Dan WalkerDan Walker commented  ·   ·  Flag as inappropriate

        1. I'd like to see this in VB as well.

        2. This kind of breaks the language spec of both C# and VB.
        Perhaps something akin to VB's Option keyword would do.. like Option NonNullable or Option Nullability Off. That would instruct VB/C# that a new syntax engine should be used. These new syntaxes would have to address the concerns people have already mentioned (eg. initialization, etc). [To be clear, I'm suggesting this be implemented as a syntax change, not through some hokey data type concept]

      • Kris VandermottenKris Vandermotten commented  ·   ·  Flag as inappropriate

        Turns out Spec# has pretty good support for non-null types. It even supports arrays of non-null types, though I personnaly do not like the way in which it does so.

        To be precise, I very much like a lot of what I read in section 1.0 of the tutorial (http://specsharp.codeplex.com/wikipage?title=Tutorial), but not what I read in section 4.1.

        BTW, note that quite a bit of what Spec# had to offer can be done in C# today with code contracts (http://research.microsoft.com/en-us/projects/contracts/default.aspx).

      • Anonymous commented  ·   ·  Flag as inappropriate

        @Kris: you can see it like the feature in C++, where you can have arrays of (and use dynamic_cast with) pointers, but not references [which bear some resemblance to nullable and non-nullable reference types in C#].

      • Anonymous commented  ·   ·  Flag as inappropriate

        @Kris: the question boils down to implementation of default(T) for a non-nullable T.

        My personal opinion would be making it just illegal, so it wouldn't be possible to have an array of C!'s. So, as a direct answer to your question, this shouldn't be compilable.

        This would make an unpleasant difference between "natively" non-nullable value types and nullable reference types, however I don't see any better solution.

        Interesting is, how is this implemented in Comega (http://research.microsoft.com/en-us/um/cambridge/projects/comega/)?

      ← Previous 1 3

      Feedback and Knowledge Base