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 :) */}
25 comments
-
Peter
commented
This would be by far my #1 feature request for C# / .NET. It would eliminate so many headaches and so much work. I don't know what is the best way to solve this problem, but if the .NET team would be willing to sacrifice backwards compatibility in the name of fixing this problem, I think it would instill a feeling that the platform is moving forward and willing to fix mistakes and not just accumulate them.
So guys, please fix this and make it such a high priority that you would be willing to break things to save effort in the future.
Whatever feature you come up with in the future, it would pale in comparison to the benefits of having nulls eliminated by the compiler. Thanks.
-
Mauricio Scheffer
commented
Dean G: that looks like a bad implementation of an option type. Just use Sasa http://sourceforge.net/projects/sasa/
-
Dean G
commented
It is a great idea. Not sure where I got this code from, but this is what I've had to do in the mean time:
///<summary>A simple structure to wrap a class reference after ensuring that the reference is not null.</summary>
public struct NonNullable<T> where T : new()
{
/// <summary>Check and wrap a value.</summary>
/// <param name = "aItem">The value to check and wrap.</param>
/// <exception cref="System.ArgumentNullException">If Value is a null reference.</exception>
/// <remarks>To pass a non null value use ?? operator.</remarks>
public NonNullable(T aItem)
{
if (aItem == null)
{
mValue = new T();
// throw (new System.ArgumentNullException("value", "That value is null"));
}
else
{
mValue = aItem;
}
//return;
}///<summary>Get a String representation of the wrapped value.</summary>
///<returns>The result of the wrapped value's ToString().</returns>
public override string ToString()
{
return (this.Value.ToString());
}///<summary>Implicit wrapping of the value.</summary>
///<returns>The wrapped value.</returns>
///<exception cref="System.ArgumentNullException">If Value is a null reference.</exception>
public static implicit operator NonNullable<T>(T aItem)
{
return (new NonNullable<T>(aItem));
}///<summary>Implicit unwrapping of the value.</summary>
///<returns>The unwrapped value.</returns>
public static implicit operator T(NonNullable<T> aItem)
{
return (aItem.Value);
}/// <summary>The wrapped value.</summary>
public T Value
{
get { return mValue; }
private set { mValue = value; }
}
T mValue;
} -
Marc Sigrist
commented
@Vladislav: Yes, non-nullable reference types would make C# more "symmetric" (with nullable value types), which is in itself a good thing from a language design perspective.
-
Vladislav Duma
commented
@IAmAI: I think Null-Object pattern is a workaround for absence of safe navigation operator (aka ".?"), which is a subject of other popular suggestion:
http://visualstudio.uservoice.com/forums/121579-visual-studio/suggestions/2216723-automaticaly-check-object-nullity-before-access-so
http://visualstudio.uservoice.com/forums/121579-visual-studio/suggestions/2372576-create-a-null-safe-dereference-operator
http://visualstudio.uservoice.com/forums/121579-visual-studio/suggestions/2873905-null-non-coalescing-operator -
Vladislav Duma
commented
@Marc: Well, I don't think this brings too much of additional complexity into the language. On the contrary, it makes the type system simpler: with your suggestion, both reference and value types can be either nullable or not. As of now, only value types have a choice.
-
Marc Sigrist
commented
As my suggestion has become somewhat popular, I would like to add more context to it. Null references were introduced in ALGOL in 1965. The language designer has famously described this as his "billion dollar mistake" (see
http://www.infoq.com/presentations/Null-References-The-Billion-Dollar-Mistake-Tony-Hoare).The error has been copied by the mainstream OO languages, inclusign C#. By now, the worldwide costs of preventing and fixing NullReferenceExceptions might easily be in the range of a billion dollars a year.
Given the seriousness of the problem, the correct thing to do would be to redesign C# (or even the .Net Framework) so that, by default, the usage of null is forbidden. To indicate that something might or might not exist, a new "Option<T>" or "Maybe<T>" type could be added, ideally with proper syntactical support in the language. An example of a .Net language who works like this is F#.
However, I don't think it is realistic to expect such a fundamental change in C#, a long-established mainstream language. Therefore, I have suggested the second-best solution, which is to add non-nullable reference types. Of course, this would make C# a bit more complicated, as we would then have four "contingency idioms" (nullable vs. non-nullable value types vs. reference types). But it would still be less complex and expensive than the combined effort of ReSharper/CodeRush, code contracts, coding conventions, documentation, and testing,
while still running the constant risk of NullReferenceExceptions. -
Alex commented
everybody who voted for this are the professionals
-
Fabio von Hertell
commented
Awesome Idea! I was thinking about sth with an attribute, but that´s way better.
-
Paulo
commented
I suggested a similar idea but now I am voting for your suggestion as it already has more votes!
Great idea!!! hehe -
Vladislav Duma
commented
@Akash: Well, are the Code Contracts constraints enforced at compile-time? If no, your suggestion doesn't bring too much.
-
Akash Kava
commented
Use code Contracts, this is a Logical check, not a language feature. Also null May come from anywhere, how do you check?
-
IAmAI
commented
This feature would be useful when using the Null Object pattern. The idea is that an instance of specific class is used to represent a null state instead of using 'null' itself. Non-nullable reference types would allow a class designer to enforce the use of the null class.
-
[Deleted]
commented
Assuming that stack/heap placement isn't a critical consideration/factor, couldn't one do this on their own with a struct via operator overloading instead of a class?
-
Justin Michel
commented
Akio, take a look at how Kotlin handles null safety...
http://confluence.jetbrains.net/display/Kotlin/Null-safetyThis means that your "nonnull(s)" scope is implemented simply as "if (s != null)". The language keeps track of whether a particular symbol has already been checked for null.
They also show how it's possible to add null safety to a large code base without having to rewrite/recompile everything.
-
Anonymous
commented
can you imagine the number of back-and-forth conversion between nullable legacy code and non-nullabe ones?
-
Akio Takahashi commented
I think that it needs to write more code at the calling sites of UI related class.
UI related classes can't be initialized at constructor in some case or intentionally (for lazy init). So fields in these class are initially null. In other situation, when UI classes represents internal state, fiedls are null as a one state of UI. For example;
class MyForm : Form {
private Item currentItem; // Item object if selected.
}
In this case, the every code passing currentItem as a Item! type argument needs non-null cast. I guess it feel tired.So, I suggest 1 additional syntax: non-null scope. Like this;
void MyMethod(string s) {
// s is typed as nullable string here.
nonnull(s) /* check that s is non null */ {
// s is treated as a non-null string in this scope.
// s can be set from string! value or passed to a out/ref string! argument.
}
s = null;
} -
JMCF125 commented
Check out Sasa (download here: http://sourceforge.net/projects/sasa/), with non-null types, option types (might be null), extension methods for anything... Take a look in here: (http://higherlogics.blogspot.pt/2010/12/sasa-v093-released.html) as well.
-
Justin
commented
I would go farther, and request an option (per project, or per file) to make the default to disallow null for fields, variables, and parameters. Then introduce a symbol or keyword to make it clear which can be null. Most importantly do it for VB too.
void foo(Bar br, Baz? bz) {
String s1 = br.getNotNull();
String s2 = bz.getNotNull(); // Compile error. bz might be null
if (bz == null) {
return;
}
String s3 = bz.getNotNull(); // Now it's OK. Compiler knows not null .
String s4 = bz.getMayBeNull(); // Compile error
String? s5 = bz.getMayBeNull(); // Now it's OK
}
For VB I would use a keyword
Sub Foo(br As Bar, Optional bz as Baz)
Optional s5 as String = bz.getMayBeNull() -
CSharpJohn
commented
Agreed. How many times have we written Contract.Requires<ArgumentNullException>(a != null); already?? Beyond a ! operator, we need declarative contracts like:
public object foo( object o, object o2, int i, int j )
where o is not null, i >= j fails with ArgumentException // Requires()
were o2 can be null // Documentation of absence of contract...
{
//...
}
where result is not null // Ensures
throws InvalidOperationException; // missing features in contracts: documentation of exceptions