BT

New Early adopter or innovator? InfoQ has been working on some new features for you. Learn more

C# Futures: Nullable Reference Types

| by Jonathan Allen on Apr 17, 2017. Estimated reading time: 3 minutes |

No, the headline isn’t a typo. One of the new proposals for C# is to assume that all reference variables are non-nullable by default. Under the new syntax, you would need to explicitly indicate when a reference variable is nullable, just as you do for value types.

As with value types, T would refer to a non-nullable type and T? would refer to a nullable type. Warnings would be generated under the following circumstances:

  • The nullable variable is dereferenced
  • A nullable variable or parameter is assigned to a non-nullable variable
  • Casting from T?[] to T[]
  • Casting from T[] to T?[]
  • Assigning a null literal to a non-nullable variable or parameter
  • The constructor doesn’t assign a value to all non-nullable fields

For the first two cases, the warning will be omitted if you use the bang operator (x!) or if the compiler can prove that a null-check has already been performed.

Implementation Details

Downlevel compilers will ignore nullability annotations, so that isn’t an issue. There will, however, have to be some sort of marker at the assembly level to indicate that the library was compiled with nullability annotations enabled.

Since all of this nullability stuff is technically a breaking change, the current plan is to allow developers to opt-in to the following categories:

  • Nullable warnings
  • Non-null warnings
  • Warnings from annotations in other files

The proposal continues:

The granularity of the opt-in suggests an analyzer-like model, where swaths of code can opt in and out with pragmas and severity levels can be chosen by the user. Additionally, per-library options ("ignore the annotations from JSON.NET until I'm ready to deal with the fall out") may be expressible in code as attributes.

This design is predicated based on trying to achieve these three goals:

  • Users can adopt nullability checking gradually as they want to
  • Library authors can add nullability annotations without fear of breaking customers
  • Despite these, there is not a sense of "configuration nightmare"

You will not be able to have a nullable and a non-nullable overload of the same method. While technically the CLR supports this, it is not part of the CLS or Common Language Specification. This means most compilers would not understand what’s happening. HaloFour explains:

modreq is not-CLS. modopt does allow for overloads, but requires specific understanding on the part of all consuming compilers since the modifier must be at the very least copied into the call signature. Both break compatibility with existing method signatures. For something that will hopefully proliferate across the entire BCL very quickly, using modopt would create a big hurdle.

Generics

Additional warnings could appear when working with generics:

  • Casting from C<T> to C<T?>, unless the type parameter is covariant (out)
  • Casting from C<T?> to C<T>, unless the type parameter is contravariant (in)
  • Using C<T?> when then type parameter is constrained to be non-null

Using “class” would constrain the generic to be non-null. Using “class?” would allow for nulls. The proposal continues:

If a type parameter is unconstrained or has only nullable constraints, the situation is a little more complex; this means that the corresponding type argument could be either nullable or non-nullable. The safe thing to do in that situation is to treat the type parameter as both nullable and non-nullable, giving warnings when either is violated.

Arrays

Arrays pose a special challenge, as it wouldn’t necessarily be possible to ensure that every slot in a non-nullable array has a value.

We cannot adequately track that all elements of an array of non-null references are initialized. However, we could issue a warning if no element of a newly created array is assigned to before the array is read from or passed on. That might handle the common case without being too noisy.

Open Design Questions

Should using default(T) be considered a warning? Or is it assumed to return T? instead of T?

Can the ? be omitted on local variables, with nullability inferred based on usage?

Can parameters auto-generate the null checks using T! x pattern?

Can nullable value types be tweaked so that you can write x.method instead of x.value.method (this would apply when x is known to be non-null such as after a successful null check)?

More Information

Rate this Article

Adoption Stage
Style

Hello stranger!

You need to Register an InfoQ account or or login to post comments. But there's so much more behind being registered.

Get the most out of the InfoQ experience.

Tell us what you think

Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

Email me replies to any of my messages in this thread

Sentence difficult to read by Loïc Lopes

As code looks the same as the text, the sentence "Or is it assumed to return T? instead of T?" isn't easy to read.

Re: Sentence difficult to read by Bam Ezu

Yes something like "Or is it assumed to return << T? instanceof T? >>"

Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

Email me replies to any of my messages in this thread

Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

Email me replies to any of my messages in this thread

2 Discuss

Login to InfoQ to interact with what matters most to you.


Recover your password...

Follow

Follow your favorite topics and editors

Quick overview of most important highlights in the industry and on the site.

Like

More signal, less noise

Build your own feed by choosing topics you want to read about and editors you want to hear from.

Notifications

Stay up-to-date with curated articles from top InfoQ editors

"You dont know what you dont know" change that by browsing what our editors pick for you.

BT