This project is read-only.


null propagating operator on structs sometimes compiles


null propagating operator on structs sometimes compiles and sometimes does not. Consider this sample, it compiles but it should not because all what Length?. does is that it lifts int to int? and then unwraps it to int.
public class C
    static void Main()
        string s = null;
        var x = s?.Length?.ToString (); // Compiles but it should fail as the second ?. is useless as it will never be null
//      var x = s.Length?.ToString (); This fails to compiler


VSadov wrote Aug 8, 2014 at 7:04 PM


var temp = s?.Length;
var x = temp?.ToString();

The second ?. is not redundant since s could be null, and then temp will be null, and then x should be null too. The idea is that s == null should result in x == null, unlike the case with regular "." where s==null will result in a NRE.

Indeed, codegen could be smarter and just produce null right after we know that s == null in "var x = s?.Length?.ToString ()". The subsequent wrapping/unwrapping of nullable could be skipped.

We are considering this as a potential optimization target, but that is an implementation detail.

s.Length?.ToString fails to compile because unlike "s?.Length", "s.Length" returns int (not int?) and as such is not a valid target of a null propagating operator.

Hope this explanation makes sense. :-)

mareksafar wrote Aug 9, 2014 at 9:09 AM

Why do you think

var temp = s?.Length;
var x = temp?.ToString();

should be same as

var x = s?.Length?.ToString ();

?. is short-circuit operation and in second case Length?. is guaranteed to be never used (reached with null). Hence this indicates more coding mistake than anything else and I don't think it adds any value to allow something what should be always removed.

VSadov wrote Aug 10, 2014 at 3:40 PM

Ah, I see. My answer was basically "because grammar says so", but the question is really - why is the grammar shaped lake that? In particular - why "?." and "." have different precedence?

I do not know exactly. It was in the grammar since the initial proposal. My guess is that the "right-associative" access was a new and unfamiliar pattern for the language and there was attempt to limit scenarios. The conditional tail of postfix operator applications would end as soon as we see anything other than ".", "[]" or "()". You are suggesting that "?." and "?[]" be included in this set.

I think, I like the idea. Since null propagation is a monadic property, changing relative precedence of "?." and "." should not affect the result of a given expression, but may result in a more efficient evaluation without a need for additional optimizations.
It will indeed force the user to use "." with value types, which seems reasonable.

I will ask around if there are other concerns about changing this. I could be missing something.


angocke wrote Aug 15, 2014 at 1:12 AM

Fixed in changeset 1a0f48ca4edf7c1f4b77a6d4b1e9ec4ae148d29e