25

I stumbled across an interesting site, where some of the new (proposed) features of C# 6.0 are addressed. You may read it here: Probable C# 6.0 features.

What I find particular interesting is the monadic null checking (also known as the null-propagation operator ?.). According to the site, the following statement

var bestValue = points?.FirstOrDefault()?.X ?? -1;

contains the monadic null check, which is currently implemented with this piece of code:

if (points != null) 
{
  var next = points.FirstOrDefault();
  if (next != null && next.X != null) return next.X;
}   
return -1;

My first glance was, hey, what the heck is written here? But after looking at the 'old' code, I am starting to like it.

However, I am also starting to get some questions, which I'd like to ask.

  • I assume that this null-propagating operator is thread safe. But how is that actually performed? Will race conditions be removed or are they persisting?
  • How would this operator handle generic types? Moreover, how would it deal with unconstrained generic types? For example, consider

    var resultAfterNullCheck = x?.Y;
    

    If the type Y here is instantiated with reference types, non-nullable value types and nullable value types, there would be nothing reasonable to do (as I cannot think of what to do, as I simply do not know what to do). So is there a default that will be returned? Or will it throw an error?

  • When looking at the example the site provides (and which I copied above) I assume that one of the main benefits of the null-propagation operator will be that it will evaluate the statement only once. However (perhaps due to my lack of knowledge of CLR), I am quite curious on how it could be performed.
    As to me, the first evaluation (if points equals null) should trigger the extension method FirstOrDefault() to trigger when points isn't null, followed by the evalation of the returned type to be null or not, if not, X will be returned. So these are in fact three evaluations combined to one? Or am I understanding it incorrectly? Will this affect speed of execution?

In other words, what will be faster, the old way of performing null checks, or this new lovely operator? I will try to examine this by performing some research as soon as the download of Visual Studio 2015 is finished... But that requires a bit of patience...

Are there any thoughts on this new operator type? Is it really still a proposed one, or can we really expect to work with this new monadic null check?

EDIT
As Matthew Watson provided a nice MSDN article discussing this (and more) topic(s), I was curious if it mentioned my earlier question regarding unconstrained generics and how this operator deals with that. Unfortunately, I haven't found an answer yet. While I will suppose that the programmer should try to prevent the usage of unconstraint generics, I can still imagine that this is sometimes not feasible. If that is the case, will a redesign be really necessary?

RvdV79
  • 2,002
  • 16
  • 36
  • 2
    It's called the ["Null conditional operator"](http://blogs.msdn.com/b/csharpfaq/archive/2014/11/20/new-features-in-c-6.aspx) now. – Matthew Watson Jan 13 '15 at 12:14
  • 1
    You can find a lot of information here https://roslyn.codeplex.com/discussions/540883. – adrianm Jan 13 '15 at 12:17
  • 2
    @MatthewWatson `if (MyEvent != null) MyEvent(this, EventArgs.Empty);` is a well-known example of what should be rewritten as `var myEvent = MyEvent; if (myEvent != null) myEvent(this, EventArgs.Empty);`: even if the access to `MyEvent` is atomic, it may change from non-null to null between the comparison and the invocation. That's the sort of thing that `MyEvent?.Invoke(this, EventArgs.Empty);` should address already, as I understand it. –  Jan 13 '15 at 12:17
  • You already showed how it will be implemented, pretty similar to the code using `if`-statements. – Lasse V. Karlsen Jan 13 '15 at 12:17
  • Ah, thanks for that site @MatthewWatson, it is quite interesting. – RvdV79 Jan 13 '15 at 12:18
  • @hvd Yes, I assume that the ?. code is translated to code which makes temporary copies of the references to avoid race conditions. – Matthew Watson Jan 13 '15 at 12:19
  • 1
    @RvdV79 Also see [this MSDN article](http://msdn.microsoft.com/en-us/magazine/dn802602.aspx). – Matthew Watson Jan 13 '15 at 12:19
  • So, @MatthewWatson, I assume that the names "Monadic null check" and "Null-propagation operator" are now obsolete / deprecated? – RvdV79 Jan 13 '15 at 12:28
  • @RvdV79 I think they are still in common use for other languages, but for C# it seems that Microsoft are calling it "Null Conditional Operator" now. – Matthew Watson Jan 13 '15 at 12:32
  • I see, well, I'll start using that terminology then. Very interesting stuff, it makes my heart beat just a bit faster than usual :) – RvdV79 Jan 13 '15 at 12:33
  • 2
    I declare that I will call it "monadic null chaining" because it sounds much more nerdy than "null conditional operator" – Stilgar Jan 13 '15 at 13:33

3 Answers3

16

You are way overthinking this. One by one, your questions:

  1. Why would you assume it's thread safe? Calling a member function isn't. This is nothing but calling a member function with a pre-check for nulls, so you only get as much thread safety as the original function guarantees.

  2. If your generic type allows null comparison (which is what this operator will use behind the scenes), then code will be emitted. If not you'll get a compile error (for example if you require the type to be a value type). That covers all cases!

  3. It is called once -- per operator, just like the normal . operator. If you say A.b.c it's still going to be two levels of indirection, and using this new operator is nothing different, it just checks for nulls too.

The real benefits of ?. are that it's semantic (you can tell at a glance what your code is trying to do) and short circuiting (makes code a lot shorter than nested ifs). You aren't going to replace every . in your old code with ?., in fact you'll probably rarely use it. But there are cases where it's going to be useful, like in Linq expressions following ...OrDefault() operations, or calling events.

Blindy
  • 65,249
  • 10
  • 91
  • 131
  • 3
    Is 1 really necessary? I don't think anyone expects `x?.f` to magically make `f` threadsafe. He was just asking whether `x?.f` removes the race condition in `if (x.f != null) x.f`. – Rawling Jan 13 '15 at 13:47
  • 4
    I've heard it before that I am overthinking stuff. Even my wife complains about it. I guess it has something to do that I am trying to understand how the mechanics are working before actually trying them. @Rawling is right with what I meant with my first question. I'll edit my question. – RvdV79 Jan 13 '15 at 13:49
  • @Rawling, I don't think he was, if you look at his code you see that he already understands that the variable is first saved on the stack, then tested, then used. – Blindy Jan 13 '15 at 13:49
  • @Blindy I've updated my question. I think I am getting it, although I still have questions regarding my second question. So I took the liberty to update that question too. – RvdV79 Jan 13 '15 at 14:56
  • @RvdV79, I'm still not sure what you find confusing about generics. You can either check if they're null or you can't, it's not Shroedinger's cat. If you can't then you get a compile error, and if you can then the correct code is emitted to the CLR. – Blindy Jan 13 '15 at 19:26
  • @Blindy, I appreciate your simple explanation, so thanks for that! I do not find generics confusing, I am mainly interested in the mechanics. That is why I am "way" overthinking this. – RvdV79 Jan 14 '15 at 07:52
  • I've had a bit more time to think of your answer. If I understand your answer correctly it would imply the following: The ?. operator always checks for null and can therefore only be applied to reference types and nullable value types. When the 'receiver' contains null, the output will always be a reference type or a nullable value. Did I understand this correctly? – RvdV79 Jan 14 '15 at 15:18
  • 1
    @RvdV79, exactly. And more specifically, anything that can be null, not just reference types and nullable types. If in C#7 they add something else that can evaluate to null without being one of those two cases, `.?` will work on it. It's like templates in C++ where they get compiled once provided a type and they can either work or not as written. – Blindy Jan 14 '15 at 15:56
8

To partially answer your first question, according to John Skeet on his blog, the null conditional operator ?. (= null propagation operator) is thread safe.

Erwin Mayer
  • 18,076
  • 9
  • 88
  • 126
  • how is the operator thread safe if the writer of the blog mentions using Interlocked.CompareExchange in order to make it thread safe? I mean it might be, but I didn't see any evidence of it in the blog post you've mentioned, did I miss something? – hapass Apr 07 '16 at 06:38
  • 1
    "The code we’ve got so far is “thread-safe” in that it doesn’t matter what other threads do – you won’t get a NullReferenceException from the above code. " Meanwhile, `Interlocked.CompareExchange` is useful "to invoke the absolute latest set of event subscribers". So it is not about thread safety but whether you want to ensure the event is fired on the most recent set of event subscribers. – Erwin Mayer Apr 07 '16 at 12:50
  • The operator basically evaluates to a method that takes x, checks for null, and if not null it executes the following code on x. If you call a method with a member variable and the member variable immediately after is set to null, the variable in your method will still have an actual object. In this sense ?. is thread safe. – Mark Gjøl Oct 13 '17 at 14:20
1

You can find everything about planned features in Roslyn project discussion. You can also try new features with console application using Roslyn like nuget-package (that means it works with Visual Studio 2013 <)

Miroslav Holec
  • 3,139
  • 25
  • 22