Null-propagating operator ?.

Topics: C# Language Design, VB Language Design
Coordinator
Apr 2, 2014 at 6:07 AM
Edited Apr 8, 2014 at 1:33 AM

Null propagating operator ?.

The ?. operator is the second-highest voted request on UserVoice
http://visualstudio.uservoice.com/forums/121579-visual-studio/suggestions/3990187-add-operator-to-c

We've discussed it in C# and VB Language Design Meeting. Mads has written up detailed notes here and here. Some questions still remain, so I'm starting a thread for general discussion of this feature.

The core idea is to save you having to write code like this all the time, with null-checks:
var temp = GetCustomer();
string name = (temp == null) ? null : temp.name;
Instead you'd write this:
var temp = GetCustomer()?.name;

How does ?. behave in sequences?

Q. How does it behave if you have several of these things in sequence? There are two possibilities on the table:
  • Left-associative
  • Right-associative
class Customer1
{
    public readonly ExtraRef extraRef = new ExtraRef();
}

class ExtraRef
{
    public readonly string name = "fred";
}

Customer1 GetCustomer1()
{
    return (RND.Next() > 0.5) ? null : new Customer1();
}

int? len1a = GetCustomer1()?.extraRef?.name?.Length;
int? len1b = GetCustomer1()?.extraRef.name.Length;
What do you expect about len1a and len1b? [edit - initially I wrote the following out wrong. I've fixed them.]
  • len1a - this is the same for both left-associative and right-associative -- it performs a null-check on GetCustomer1(), and if that succeeds, then it will perform null-check on extraRef and name.
  • len1b - under left-associative it is a compile-time error. But under right-associative, it performs a null-check on GetCustomer1(), and then skips the null-check on extraRef and name.
Note: I constructed this example so that, if GetCustomer1() returns non-null, then I as the programmer know (from readonliness) that extraRef and name will both be non-null. The question is, is there some way to communicate this fact to the compiler, to avoid superfluous null-checks? Left-associative says there isn't; right-associative says there is.

(I benchmarked about a 5% perf overhead of doing those extra null-checks in the case where GetCustomer1() returns non-null)
class  Customer2
{
    public readonly ExtraStruct extraStruct = new ExtraStruct {age=29};
}

struct ExtraStruct
{
    public int age;
}

Customer2 GetCustomer2()
{
    return (RND.Next() > 0.5) ? null : new Customer2();
}

int? age2a = GetCustomer2()?.extraStruct?.age;
int? age2b = GetCustomer2()?.extraStruct.age;
What do you expect about age2a and age2b ?
  • age2a (how you must write it under left-associative) - this performs a null-check on GetCustomer2() and if this succeeds then, thanks to compiler-optimization and despite what's written, it knows it can skip the null-check on extraStruct.
  • age2b (how you must write it under right-associative) - this performs a null-check on GetCustomer2() and if this succeeds then, because of how you wrote it, it skips the null-check on extraStruct.
Here, extraStruct is a structure and can never be null. So it doesn't make sense to null-check it. Should this fact be expressed as a compiler optimization in age2a? Or should it be expressed in syntax in age2b?
var x = GetCustomer1()?.extraRef?.name?.Length
==>
var explainingVariable = GetCustomer1()?.extraRef;
var x = explainingVariable?.name?.Length;
  • Is this a valid refactoring?
    • left-associative : it is a valid refactoring
    • right-associative : it's an invalid refactoring
  • How would you add parentheses to make the order explicit?
    • left-associative : x = ((GetCustomer1()?.extraRef)?.name)?.Length
    • right-associative : x = GetCustomer1()?.(extraRef?.(name?.Length))
You can see why we call them left-associative vs right-associative. It has to do with how you'd put parentheses into the expressions if you were writing them out explicitly.

Incidentally, there are other places where you can't just introduce an explaining variable. For instance, in var y = a * b + c * d, you can't just introduce an explaining variable for the first three parts var ev = a * b + c; var y = ev * d;. In this case though it's because of precedence, not because of associativity.

[NOTE: that + is meant to be a PLUS sign. I don't know what's up with the markdown...]

Eric Lippert wrote a great blog on the associativity of the ?? operator: http://blog.coverity.com/2013/10/23/null-coalescing-bugs/#.Uzurzo1OV3Q

Some other idioms with ?.

// Call Dispose only if x is non-null:
x?.Dispose(); 


// Trigger an event only if it's non-null
// (not needed in VB, since this is already built into RaiseEvent statement)
event EventHandler OnFired;
void Fire()
{
    OnFired?.Invoke(this, new EventArgs());
}

Codegen for ?.

I asked some CLR experts about what assembly code would be generated by the JIT for the ?. operator, and filled in some details from my hazy memory of OS architecture...

The question was, where does NullReferenceException currently get generated? When you do GetCustomer1().extraRef, and GetCustomer1() happens to return null, and so it fires a NullReferenceException, does that happen because the JIT implicitly generates a null-check?

No. The answer is that the NullReferenceException is generated at a lower level. More specifically, in between CPU and RAM there’s a chip called "Memory Management Unit (MMU) / Page Table". Every single time a thread accesses an address in the process’s virtual address-space, the MMU looks up the address in that page table to find where the address is in physical memory. If the virtual address isn’t yet mapped to a page of memory, then the MMU generates a page-fault which the OS has to handle, e.g. by paging in from disk. The CLR reserves addresses at the bottom of virtual address space but never actually pages them in. If ever an instruction tries to look up any address there, then the MMU generates a fault, and the CLR responds to it by generating a NullReferenceException.

The codegen for x?.y would probably be something like this...
mov rax, X
test rax, rax
beq :lbl
mov rax, [rax + k]
:lbl 
[Note: that + is meant to be a PLUS sign. I don't know what's up with the markdown...]
Apr 3, 2014 at 7:19 PM
Edited Apr 3, 2014 at 7:19 PM
I would also suggest to add a generic monadic bind for nulls - i.e. an operator which evaluates the left operand, and if it is not null, then evaluates and returns the right operand, otherwise returns null (so kinda a reverse of ??). This would be handy for covering all the various cases that are not covered by the shorthand ?. syntax, such as passing the value as a parameter to a method. For example, assuming that operator is ?::
return s ?: Trim(s);
Apr 3, 2014 at 7:36 PM
When passing a value as a parameter to a method, wouldn't you want to let the method decide how to best handle the null argument? If the method doesn't handle the null argument the same way as the caller would prefer, the current syntax is explicit and isn't really much of a nuisance.
return s ? Trim(s) : null; // Doesn't seem so bad
Apr 3, 2014 at 7:57 PM
Edited Apr 3, 2014 at 8:33 PM
Surely the question is simply whether
a?.b.c
should mean
(a == null ? null : a.b).c
or
(a == null ? null : a.b.c)
I think it’s easy to see that the first one is much less useful. It would mean that
s?.Trim().Substring(x, y)
would always throw if s is null, thus entirely negating the benefit of ?.. Clearly, it should mean the latter.

This does not make it a right-associative operator. Instead, it means that the grammar needs to define “chains” of applications of this operator. In particular,
a?.b.c
should NOT be parsed as
MemberAccessExpression:
    Safe = false
    MemberName = c
    Instance = MemberAccessExpression:
        Safe = true
        MemberName = b
        Instance = a
but rather as something like:
MemberAccessExpression:
    Instance = a
    Chain = [
        [ Safe = true, MemberName = b ],
        [ Safe = false, MemberName = c ]
    ]
This way, the effect of the null check propagates through the chain of member accesses as the programmer intended.

This approach is extensible, too. The same syntax can be used for safe indexing and safe invocation. For example:
myList?.Items?[0].SomeDelegate?(x)
would mean the effective equivalent of:
myList == null ? null :
    myList.Items == null ? null :
        myList.Items[0].SomeDelegate == null ? null :
            myList.Items[0].SomeDelegate(x)
but without the repeated reevaluation. Note that the programmer can easily short-circuit the entire chain (as is clearly intended), while simultaneously communicating that some accesses (in this case, the result of myList.Items[0]) should not be null-checked.
Apr 3, 2014 at 7:57 PM
Edited Apr 3, 2014 at 8:01 PM
When passing a value as a parameter to a method, wouldn't you want to let the method decide how to best handle the null argument?
Generally speaking, no, because by convention most would throw ArgumentNullException rather than return null.
If the method doesn't handle the null argument the same way as the caller would prefer, the current syntax is explicit and isn't really much of a nuisance.
Currently, you rather have to write:
return s != null ? Trim(s) : null;
or maybe rather:
return s == null ? null : Trim(s);
(so that the most important expression is visually at the end, and better separated)

It's not too bad on its own, yes. The problem is that it doesn't chain well with multiple invocations. Granted, the ?: syntax doesn't do so, either - to chain, it would need some way to capture the expression on the left side, and then refer to it on the right side. E.g. with it:
return s ?: TrimLeft(it) ?: TrimRight(it);
This also has the bonus effect in that s can then be an arbitrary complex expression with side-effect, like Foo(s1+s2).

I suppose at this point it all just becomes a thinly veiled request for let (or other way to bind variables in expressions). E.g. assuming we had let ... in ..., this could be written as:
return let it = Foo(s1+s2) in it == null ? null : let it = TrimLeft(it) in it == null ? null : TrimRight(it)
and then perhaps with a null-propagating let? version:
return let? it = Foo(s1+s2) let? it = TrimLeft(It) let? it = TrimRight(it) in it;
Though I'd still like some syntactic sugar for the most common "map left side to something convenient" operation. Say, |> could be the non-null version:
return (s1 + s2) |> (it.Length > 10 : it.Substring(0, 10) : it);
and then ?|> is the null propagating one:
return Foo(s) ?|> TrimLeft(it) ?|> TrimRight(it);
Yes, this is definitely getting much more complicated than what I originally had in mind...
Apr 4, 2014 at 3:57 PM
If something like this gets implemented, it would be considerably more powerful if it were implemented as a language pattern (ala LINQ) rather than as a null-specific fix.

I'd absolutely love to use this kind of technique for other types, e.g. option types, possibly failing tasks, etc.

For example, I've used an option-like type to communicate a value or an annotated error condition. Doing so in C# now is doable but fairly messy (also because there's no really clean way to implement a discriminated union), but potentially quite valuable.
Apr 4, 2014 at 7:57 PM
pminaev wrote:
I suppose at this point it all just becomes a thinly veiled request for let
Just to note, LET can be achieved by a combination of 'declaration expressions' (already in the Roslyn preview) and 'expression sequences' (not yet implemented). It'd look like this:
var x = (var s = expr; s == null ? "" : TrimLeft(s));
Apr 4, 2014 at 7:59 PM
emn13 wrote:
If something like this gets implemented, it would be considerably more powerful if it were implemented as a language pattern (ala LINQ) rather than as a null-specific fix.
emn13, that's an intriguing idea, but I don't have any clear idea of how to implement it. Could you spell out a bit more what you're thinking? For instance, in this example, what kind of pattern would s?.Length expand to?
string s = strings.GetFirstOrDefault();
int? len = s?.Length;
Apr 5, 2014 at 3:46 PM
Edited Apr 5, 2014 at 4:02 PM
I've been a ?. operator promoter since a long time ago but I didn't though about the precedence problem. Now I'm concerned.

So, imagine you have a chain like this and you're brave enough to ignore Law of Demeter
 Customer.Address.Country.IsoCode
You trust that you have a customer, addresses have a country, and countries have an IsoCode, but Address is optional in customer.

There are two options:

left-associative: writing ?. contaminates all the next code
Customer.Address?.Country?.IsoCode2 

Cons: It clutters all the chain and promotes a 'just write ?. always' code style.
Pros: It's easy to reason about, every sub expression makes sense and has a type

right-associative: writing ?. just after each optional field
Customer.Address?.Country.IsoCode
Pros: It makes clear with are the optional fields
Cons: You can not reason about the expressions easily anymore, and you have to take arbitrary decisions to when this chain ends:

Lets imagine we have a GetCountry() extensions method on IsoCode type.
 Customer.Address?.Country.IsoCode.GetCountry()
I assume this should be interpreted like
Customer.Address?(.Country.IsoCode.GetCountry())
But what if we want to use the extension method explicitly:
CountryExtensions.GetCountry(Customer.Address?(.Country.IsoCode))
Then the chain will be broken. And what about operators, could this work?
Customer.LastInvoice?.Amount # "€"; 
Note: # should be a plus symbol, codeplex problem

And if the answer is yes, what about this?
"$" #  Customer.LastInvoice?.Amount;   
Apr 5, 2014 at 4:34 PM
We actually have a TryCC extension method defined like this:
        public static R TryCC<T, R>(this T t, Func<T, R> func)
            where T : class
            where R : class
        {
            if (t == null) return null;
            return func(t);
        }
The method takes advantage that you can call extension methods on null values.

The thing is that with this approach the precedence is clear:
Customer.Address.TryCC(a=>a.Country.IsoCode)
And also has no problem with any other kind of expression that are not just a chain of dots.
Customer.LastInvoice.TryCS(a=>a.Amount + "€")
The problems of course is the syntax clutter: instead of just a ? you have to write 12 characters!.
Customer.LastInvoice?.Amount + "€"
But maybe we could reduce the clutter...

The reason I need to call it TryCC, instead of just Try, is because the compiler can not choose the right overload when there are class / structs constraint in generic methods TryCC stands for Class-Class. So I've a TryCS, TrySC, TrySS. The overloads that take nullables can be properly resolved.

Even if overload resolution looks like a complicated part of the compiler, maybe adding that won't be that hard
Customer.LastInvoice.Try(a=>a.Amount + "€")
--> 2 characters removed

Also, I think C# could have a better syntax for lambdas with just one parameter, what about using @ for it?

The @ will be bound to the closes lambda if it has just one parameter, and possibly not valid inside nested lambdas, but could make many queries simpler:
Invoices.Where(@.Amount > 10).Select(new { @.Id, @.Customer })
And also improve strongly typed reflection, filling the missing memberof operator:
PropertyInfo = Customer.Propery(@.Id)
So it will look like this being used with Try method
Customer.LastInvoice.Try(@.Amount + "€")
--> 3 characters removed

So this solutions stills adds more clutter but is build on more general language features and solves the associativity proplem. What you think?
Apr 5, 2014 at 10:17 PM
Edited Apr 5, 2014 at 10:23 PM
I think you should avoid writing code like this:
Customer.Address?(.Country.IsoCode.GetCountry())
This is not valid code and it is not clear what is meant. However, I think I understand what you mean in this case. You’re asking how to call the extension method even if Customer.Address was null. The answer is of course parentheses:
Customer.Address?.Country.IsoCode.GetCountry()
would mean the effective equivalent of
var tmp = Customer.Address;
tmp == null ? null : tmp.Country.IsoCode.GetCountry()
(thus, GetCountry() is only called when tmp is not null), while
(Customer.Address?.Country.IsoCode).GetCountry()
would mean the effective equivalent of
var tmp = Customer.Address;
(tmp == null ? null : tmp.Country.IsoCode).GetCountry()
(thus, GetCountry() is always called).

The reason I need to call it TryCC, instead of just Try, is because the compiler can not choose the right overload
Actually it can, with a trick. I have such an extension method too, and in my case it’s called NullOr. I think Try is a very bad name because try already means something unrelated in C#; try has to do with exceptions, but your extension method does not.

The trick is that putting the constraints on the extension methods is not quite enough; you have to put the same constraints on the delegate types that you use as parameters. Here is my code: http://pastebin.com/vdS1uNu1

Invoices.Where(@.Amount > 10).Select(new { @.Id, @.Customer })
This code is highly ambiguous. How should the compiler decide which of the following you meant?
Invoices.Where(x => x.Amount > 10).Select(new { y => y.Id, z => z.Customer })
Invoices.Where(x => x.Amount > 10).Select(y => new { y.Id, y.Customer })
x => Invoices.Where(x.Amount > 10).Select(new { x.Id, x.Customer })
However, we are getting side-tracked from the topic of this thread. I think we should discuss only the ?. feature here, not lambda expressions or type inference. Consider opening a new thread for those separate topics.
Apr 6, 2014 at 12:19 AM
Edited Apr 6, 2014 at 12:33 AM
Hi Timwi,
The trick is that putting the constraints on the extension methods is not quite enough; you have to put the same constraints on the delegate types that you use as parameters. Here is my code: http://pastebin.com/vdS1uNu1
You are the man! This trick for solving the overload it's really clever. How you come up with it? It will have saved me lot of time explaining the difference of the TryCC overloads if I knew it years ago!

The fact that you can parenthesize simplifies the problem a little bit and relieves my concerns about the operator, so I like it more now.

Still, the expression
MemberAccessExpression:
    Instance = a
    Chain = [
        [ Safe = true, MemberName = b ],
        [ Safe = false, MemberName = c ]
    ]
It's a bad solution. It's really not about chains of MemberAccessExpression. MethodCallExpression at least should also be included in the same chain, making the AST quite strange.

This AST will also propagate to the System.Expression namespace, breaking LINQ providers (except if the chain happens only if there's a ?. operator, in which case we will 'only' need to add some code duplication for MemberAccessExpression/MethodCallExpression).

Also, the solution is limited in the sense that it only contemplates the . operator, ignoring binary operators, method invocation as an argument (i.e.: Math.Abs()), etc... that will be also useful.

So, I'm still not convinced. I prefer my solution with one argument lambdas, even if, just for this case, the lambda could be compiled away and inline in this same method.

I've copied your concerns and answered to them here:
Sorter syntax for lambda expression with just one parameter https://roslyn.codeplex.com/discussions/541330
Apr 6, 2014 at 4:03 PM
Edited Apr 6, 2014 at 4:06 PM
I admit I hadn’t thought of the System.Expression namespace. That would be an interesting thing to think about. However, it does not negate the parse tree I’ve suggested; it’s the only way this can be parsed such that it is in line with the programmer’s intention.
It's really not about chains of MemberAccessExpression.
I tried to keep it simple by sticking to member access. However, in my proposal, the same AST node type would be used for method and indexer invocations. Thus my own example of
myList?.Items?[0].SomeDelegate?(x)
would turn into a parse tree resembling the following:
MemberAccessExpression:
    Instance = myList
    Chain = [
        [ Safe = true, Member = get_Items() ],                  // Property getter
        [ Safe = true, Member = get_Item(int), Args = [ 0 ] ],  // Indexer getter
        [ Safe = false, Member = get_SomeDelegate() ],          // Property getter
        [ Safe = true, Member = Invoke(Foo), Args = [ x ] ],    // Delegate .Invoke
    ]
Can you explain further why you think it’s “a bad solution” and why “it’s really not about chains”? In my mind, it is all about chains: you need the null-checking semantics to “seep into” all subsequent member/indexer access/invocations until the point up to where the programmer intends the null-check to go (= the end of the chain).

It is true that I have not addressed binary operators; however, I think this is completely in line with the programmer’s intention. If you write an expression like this:
person.?Address.City ?? "<unknown>"
which of the following interpretations do you think is the most likely intention?
// ① We’ve already discarded this one: it would still throw if person is null
// and thus negate the benefit of the feature
var tmp = person == null ? null : person.Address;
tmp.City ?? "<unknown>"

person.?Address.City ?? "<unknown>"
└─────────────┘  extent of the perceived chain

// ② I think this is the most likely intention
var tmp = person == null ? null : person.Address.City;
tmp ?? "<unknown>"

person.?Address.City ?? "<unknown>"
└──────────────────┘  extent of the perceived chain

// ③ This is the only other possible interpretation.
// In this example, it is clearly not what was intended.
person == null ? null : (person.Address.City ?? "<unknown>");

person.?Address.City ?? "<unknown>"
└─────────────────────────────────┘  extent of the perceived chain
I’ve looked at various expressions with binary operators and I found interpretation ② above to be the most likely intention in all of them. Can you think of a case in which interpretation ③ would be more likely intended than ②?
Apr 6, 2014 at 4:45 PM
Edited Apr 6, 2014 at 4:46 PM
I think 2 in the above example should be the intended interpretation. The place where this operator is going to be used a lot by my team is with EF and partial classes, something like:
 partial class Customer
 {
      CountryName
      {
          get
          {
              return this.Address.?Country.?Name??"None";
          }
      }
 }
Where the Null propagating operator is combined with the default value one to walk a chain, and return a default if any part of the chain doesn't exist.
Apr 6, 2014 at 5:02 PM
This:
x?.y?.z
Should mean this:
(x == null ? null : (x.y == null ? null : x.y.z))
Or more specifically:
if(x==null) return null;
if(x.y==null) return null;
return x.y.z;
Left asociative if correct.
?. should have the same priority as .
Apr 6, 2014 at 7:07 PM
Hi Timwi,

I completely agree with you that the right-associative is a better option to than left-associative. Code should have ?. only on the optional fields, not contaminating the rest of the chain.

But there are still two problems with the implementations.

While I'm not an expert in the Roslyn nodes, I'm quite used to System.Expresion and I think we can reason using System.Expression terminology with no mismatch.

So, before expressing my concerns:

A brief introduction to System.Expression using some pseudo-code for sort
2 + 3
BinaryExpression(
    ConstantExpresson(2),
    ConstantExpression(3), 
    +)

person.Name
MemberExpression(
    ConstantExpression(person), 
    PropertyInfo("Name"))

person["Name"] // indexer
MemberExpression(
    ConstantExpression(person), 
    PropertyInfo("Item"),
    ConstantExpression("Name"))

person.ToString()
MethodCallExpresion(
      ConstantExpression(person),  //object
      MethodInfo("ToString"), //method
      null) // no aditional arguments      

Database.Save(person) //Extension method used as static method
MethodCallExpresion(
      null, // no instance
      MethodInfo("Save"), //method
      ConstantExpression(person)) // person is the first parameter!

person.Save() //Extension method!!
MethodCallExpresion(
      null, // no instance
      MethodInfo("Save"), //method
      ConstantExpression(person)) // person is the still first parameter!
Note: I've choosed ConstantExpression(person) instead of ParameterExpession("person", typeof(Person)) for pedagogic purposes

I didn't include delegate invocation because is looks that is not going to be included, fall-backing to calling the Invoke method, but will be just one case more.

Let's see how a complex expression is represented then
Save(person.Name["0"].ToString().Save())

MethodCallExpresion(
       null,
       MethodInfo("Save"),
       MethodCallExpresion(
             null,
             MethodInfo("Save"),
             MethodCallExpression(
                   MemberExpression(
                        MemberExpression(
                            ConstantExpression(person),
                            ProperyInfo("Name")),
                        ProperyInfo("Item"),
            ConstantExpression("0"))
            MethodInfo("ToString"))))
Every expression node has a type, some child nodes, and defined rules that are checked for composition in a type-safe manner.

Also, the same node (i.e MethodCallExpression) is used right now in every single method call, independently of whether it is inside of a BinaryExpression, LambdaExpression, etc..

Concern n°1: Expression node duplication

I've two problems with your MemberAccessExpression.

First, a superficial one: it should be called DotChainExpression, because it's not just about MemberExpression. MethodCallExpression are just as important in the Chain.

Secondly, a deeper one: the nodes you have on your chain, do not form a tree but a list. Due to that, new alternative nodes have to be created:
Save(person?.Name["0"].ToString().Save())

MethodCallExpresion(
       null,
       MethodInfo("Save"),
       DotChainExpression(
             MethodCallChainElement(null, MethodInfo("Save"), ??),
             MemberChainElement(??, ProperyInfo("Item"), ConstantExpression("0")),
         MethodCallChainElement(??, MethodInfo("ToString"))))
This duplication means that now every refactoring, linq provider, etc.. that has to do with MethodCallExpression, has to think also about MethodCallChainElement because they are structurally different classes. Same for MemberExpression.

This is a bad AST design, but we could solve it retaining the tree structure, defining DotChainExpression like this:
DotChainExpresion(
    leftExpresion, 
    parameterExpression,
    rightExpression)
Save(person?.Name["0"].ToString().Save())

var nnp = ParameterExpression("notNullPerson", typeof(Person));

MethodCallExpresion(
       null,
       MethodInfo("Save"),
       DotChainExpresion(
             ParameterExpression("person", typeof(Person)),
             nnp, 
             MethodCallExpression(
             null,
                MethodInfo("Save"),
                MethodCallExpression(
                    MemberExpression(
                        MemberExpression(
                             nnp
                             ProperyInfo("Name")),
                        ProperyInfo("Item"),
                        ConstantExpression("0"))
                    MethodInfo("ToString")))))
The additional ParameterExpression represents the cached value of the leftExpression, that is calculated just once.

This solution will work at the expression level, but requires that the compiler takes some (in my opinion) arbitrary decisions.

A DotChainExpresion expression will be created on every ?. operator, taking in rightExpression any node that is:
 * A MemberExpression for witch the ?. is already in the Expression propery (left), whether it is a normal access propery or a parametrized one (Indexer)
 * A MethodCallExpression for witch the ?. is already in the chain on the Object propery (left) or in the first argument of an extension method call _that is used as an Extension method_. 
So the compiler will need to convert:
person.Contry.IsoCode
MemberExpression(
   MemberExpression(
      ConstantExpession(person),
      ProperyInfo("Country")),
   ProperyInfo("IsoCode"));
Into something like this
person.Contry.IsoCode

var nnp = ParameterExpression("notNullPerson", typeof(Person));
DotChainExpresion(
   ConstantExpession(person),
   nnp, 
       MemberExpression(
          MemberExpression(
             nnp,
             ProperyInfo("Country")),
          ProperyInfo("IsoCode")));
Look how the ConstantExpession(person), that before was a inner children, now is almost parent!.

But even at the complexity of the AST parser, that should work, so my concern n° 1 could be fixed.

Concern n° 2: User case limitations

Due to the (in my opinion) arbitrary decisions to determine what should be added in the ParameterExpression rightExpression argument, the developer can not use the operator in many useful situations.

Maybe your example, coallesce operator, is not one of those but there are others, here there are three:
Invoice?.Amount.Abs() //doesn't work because is not an extension method

var amount = Invoice?.Amount; 
amount == null ? null : Math.Abs(amount); //horrible fallback

Invoice.Try(a=>Math.Abs(a. Amount)) //Using Try method is not a problem
Invoice.Try(Math.Abs(@Amount)) //And with short one param lambda expression even better
Invoice?.Amount + " €" //will write " €" instead of "" when no invoice 

var amount = Invoice?.Amount; 
amount == null ? null : (amount + " €"); //horrible fallback

Invoice.Try(a => a.Amount + " €") //Using Try method is not a problem
Invoice.Try(@Amount + " €") //And with short one param lambda expression even better
person?.Sex == Male? "M" : "F"  //will return "F" when person is null 

var sex = person?.Sex; 
sex == null ? null : (sex == Male  ? "M" : "F"); //horrible fallback

person.Try(p => p.Sex == Male ? "M" : "F") //Using Try method is not a problem
person.Try(@p.Sex == Male ? "M" : "F") //And with short one param lambda expression even better
So my concern is that, under the covers, the 'chain after the ?. operator' is just a hidden lambda with some arbitrary limitations.

Actually, the AST can be easily transformed:
DotChainExpresion(
    leftExpresion, 
    parameterExpression,
    rightExpression)
Is equivalent to my solution
MethodCallExpression(
    null, 
    MethodInfo("Try"),
    leftExpresion, 
    LambdaExpression(
        parameterExpression,
        rightExpression)
Buy my solution let's any kind of expression on rightExpression, while DotChains only allows some MethodCallExpresions, and all the MemberExpresson, missing all the others (there are like 20).

The DotChainExpression is sorter, it's true, but implementing sorter lambda expression with just one parameter will reduce the difference, and improve other unrelated scenarios (LINQ queries, strongly typed reflection, etc..). This is a good symptom for a language feature.

PD: I hope C# team doesn't ban me after this long post
Apr 7, 2014 at 12:34 AM
I fully understand you. Of course you are right that your .Try/my .NullOr can do everything that ?. can do, but ?. can’t do everything those methods can do, making ?. feel limited.

If you want to compile ?. into Expression types that already exist, you can actually do that even without Try/NullOr by having the compiler generate the entire null check:
var p = Expression.Parameter(typeof(Person));
var rightExpression = ...;  // compile the rest of the chain using “p” for the instance object

var ncp = Expression.Parameter(typeof(Person));
Expression.Invoke(
    Expression.Lambda(
        Expression.Condition(
            Expression.MakeBinary(ExpressionType.Equal, ncp, Expression.Constant(null)),
            Expression.Constant(null),
            Expression.Invoke(Expression.Lambda(rightExpression, p), ncp)),
        ncp),
    leftExpression)
This would be a possible way to represent the ?. expression without introducing new expression node types.

However, it would complicate the situation for LINQ providers, wouldn’t you agree? They would now have to support arbitrary lambda calculus. Do they already do that? I haven’t tried feeding them expression trees with nested lambda invokes. Given that we’re discussing the ?. feature, which is limited to specific kinds of null checks, I like to think about how to design an Expression API for it that doesn’t require this complexity.

I envisage the DotChainExpresion constructor to look like this:
DotChainExpresion(
    instanceExpresion, 
    params DotChainElement[] elements)
and your example expression would be represented as follows:
Save(person?.Name["0"].ToString().Save())

MethodCallExpresion(
    null,    // assuming the outer Save is a static method
    MethodInfo("Save"),
    DotChainExpression(
        personParameter,  // = ParameterExpression("person", typeof(Person))
        // (params array starts here)
        MemberChainElement(ProperyInfo("Item"), ConstantExpression("0")),
        MethodCallChainElement(MethodInfo("ToString")),
        MethodCallChainElement(MethodInfo("Save"))))      // inner Save, which is can be an instance method or a static (extension) method
In this example, I’m assuming that DotChainElement would be an abstract class from which MemberChainElement and MethodCallChainElement would be derived. It could also simply be a single class, DotChainElement, that takes any MemberInfo. This detail could be debated separately. Overall, this is a perfectly fine way to represent this specialized syntax.
This duplication means that now every refactoring, linq provider, etc.. that has to do with MethodCallExpression, has to think also about MethodCallChainElement because they are structurally different classes. Same for MemberExpression.
Refactoring tools will have to be able to work with the new syntax no matter which way you represent it.

It is true that introducing a new node type will require that LINQ providers add new code to handle it. However, in the alternative they would have to add (significantly more complex) code to handle lambda calculus. (Note that MemberChainElement and MethodCallChainElement are not expression nodes because they are not expressions. Instead they are simple data classes that describe the elements that make up a DotChainExpression. LINQ providers would need to implement one new node type: DotChainExpression.)
Apr 7, 2014 at 7:11 AM
I haven't add support for our Try method because it is useless in SQL. All the . operators are already implemented as left joins, so equivalent to ?. operators. There's no easy way to throw NullReferenceException on the row of a null FK on SQL.

But this is only true for SQL LINQ providers, for other LINQ providers it will make perfect sense, and Roslyn refactorings and other language services should face similar problems.

So, with my experience using LINQ providers:

1.- I will much happier implement support for the Try method. Implementing lambda application and replacement is something you already have to do. All the LINQ queries use lambdas and queries can be nested! I could add suppor in line 1 hour.

2.- Implementing
DotChainExpresion(
    leftExpresion, 
    parameterExpression,
    rightExpression)
won't be that hard either, I will have to support one node type more, DotChainExpresion, but the rest of the code won't be affected. 2 Hours.

3.- Implementing
DotChainExpresion(
    instanceExpresion, 
    params DotChainElement[] elements)
Beause of the duplication of MemberChainElement and MethodCallChainElement. This is MUCH harder. Lots of code will be affected because MethodCallExpression and MemberExpression are quite used already, and will have to be duplicated. Lots of maintainability problems in the future. And also I still have some questions:
  • How you know witch is the previous sub-expression in the chain for instance methods / extension methods.
  • Who makes the Type checking on DotChainExpression? DotChainExpression itself or each XXXChainElement?
I think, if DotChainExpresion should be implemented, alternative 2 is much simpler and preserves the tree structure.

So
Refactoring tools will have to be able to work with the new syntax no matter which way you represent it.
Number 3 is much harder to work with than number 2
Apr 7, 2014 at 4:18 PM
Whoa... I never imagined that right-associative could even be an option.
It is indeed more powerful, but also much more complex, since we have to understand and remember the rule for deciding when the "dotchain" end.

People would never expect that such a simple-looking operator would have such a subtle behaviour.
That's why I think left-associative is better.

Yes, that means we would have to write a?.b?.c "instead" of a?.b.c, but I don't think this will be a problem to anyone in practice.
Apr 7, 2014 at 6:54 PM
It’s fantastic to have language design at the community level. But this is a gnarly problem and at the end, I think we’re going to have to trust somebody to just make the call. That’s why ultimately we have language keepers – and we are lucky to have good ones.

The subtlety of this problem is such that I’m not seeing today (although I thought I understood this problem) why 2b in the original example is a compile time error with left associative. Lucian or someone, could you explain that?

These two things make me feel left associative is the best way. Not because it is good, but because right associative is flawed and the feature is too valuable to skip.

__var x = GetCustomer1()?.extraRef?.name?.Length
==>
var explainingVariable = GetCustomer1()?.extraRef;
var x = explainingVariable?.name?.Length;
_

_
Programmers would expect this to be a valid refactoring -> Left associative

Well stated by Olmo

___left-associative: writing ?. contaminates all the next code
Customer.Address?.Country?.IsoCode2

Cons: It clutters all the chain and promotes a 'just write ?. always' code style.
Pros: It's easy to reason about, every sub expression makes sense and has a type

_right-associative: writing ?. just after each optional field
Customer.Address?.Country.IsoCode
Pros: It makes clear with are the optional fields
Cons: You can not reason about the expressions easily anymore, and you have to take arbitrary decisions to when this chain ends:

__

“You cannot reason about the expressions easily anymore” Therefore, it does not work in the language. Ultimately the most important thing for a computer language is that it does the think the humans think it will do.

The extension method question is interesting (also raised by Olmo). With a GetCountry extension, these are no longer equivalent (the first skips the call, so is more efficient).
Customer.Address?.Country.IsoCode.GetCountry()
CountryExtensions.GetCountry(Customer.Address?(.Country.IsoCode))
There might be languages where the correctness of right associative or the lack of pollution with many ?. would supersede clarity. But I don’t think C# or Visual Basic are those languages. I think the most important factor in language decisions are whether it results in code that is easy for a slightly above average programmer to understand and reason about.
Apr 7, 2014 at 8:26 PM
I've been back and forth with this because I really want to keep it simple.

Most C# operators are left-associative, so my first instinct is to be left-associative. Even with the possible clutter of __?.__s.

However, since the null coalescing operator (??) is right-associative and this seems to be the closest in semantics with the null propagating (?.) operator, I think the null propagating operator should be right-associative.
Apr 7, 2014 at 10:35 PM
Edited Apr 7, 2014 at 10:35 PM
I'm not happy with the left/right associative terminology.

I think it should be used only for binary (or ternary) expressions:
a + b + c + d 
left-associate: ((a + b) + c) + d
right-associative: (a + (b + (c + d)))
But MemberExpression does not consist on two expression. Instead it has an Expression and a Member (Field or Property). The member has a type but not a type on its own!.
a.b.c.d
left-associate: ((a.b).c).d 
right-associative: a.(b.(c.d)) -> makes no sense
So I think a better nomenclature is:

1.- Trivial-polluter:
//You should write
GetCustomer1()?.extraRef?.name?.Length;  

//And will get compiled to
var c = GetCustomer1();
var er = c == null ? null : c.extraRef;
var n = er == null ? er.name; 
n == null ? null : (int?)n.length
2.- Complex-clean:
//You should write
GetCustomer1()?.extraRef.name.Length;

//And will get compiled to: 
var c = GetCustomer1()?
c == null ? null : (int?)c.extraRef.name.Length
As I've stand. If I'll have to chose I'll go for 2 but I'll rather choose:

3.- Optimized lambda:
//You should write
GetCustomer1().Try(c => c.extraRef.name.Length);
//Or
GetCustomer1().Try(@.extraRef.name.Length);

//And will get compiled to: 
var c = GetCustomer1()?
c == null ? null : (int?)c.extraRef.name.Length
It's a little longer but:
  • It's more general
  • The developer just has to learn a new method, not a language feature
  • The compiler could understand the pattern and remove the lambda altogether for performance reasons. With meta-programming for method invocations even a library could do it!
Apr 7, 2014 at 10:51 PM
Olmo, how would you write the "Try" method version when name might be null as well and so needs its own null-check?
Apr 7, 2014 at 10:55 PM
I'm probably a bit late to the party, but it seems that code which would want the value of foo.bar when foo is not null would, in many cases, want a value other than null when foo is null. Is there any planned way to handle cases where the default value should be something other than null (as would be necessary if the expression result was supposed to be a value type, or if null was a legitimate value for the member to be accessed, but should not be the default value [precluding use of ?? after ?.?

I would suggest that foo?.bar : boz should be equivalent to (var temp=foo; temp != null ? temp.bar : boz), and that such equivalence should hold even when foo.bar is a non-nullable value type. It may be helpful to have the : boz expression be optional in cases where there would only be one sensible way of parsing the resulting expression, but forbid compilation of code which could be parsed in two or more semantically-different ways. Would that seem practical?
Apr 7, 2014 at 11:11 PM
Edited Apr 7, 2014 at 11:11 PM
ljw1004, it's written up
    public static R TryCC<T, R>(this T t, Func<T, R> func)
            where T : class
            where R : class
        {
            if (t == null) return null;
            return func(t);
        }
Works because you can call extension method on null values.
Apr 8, 2014 at 1:21 AM
Consider the refactoring part with the value type example:

int? age2b = GetCustomer2()?.extraStruct.age;

This would refactor t, assuming left associativity:

var explaingVar = GetCustomer2()?.extraStruct;
int? age2b = explainingVar?.Value.age;

Note the injection of .Value

So maybe, regardless of left or right, the ?. should be extended to nullable types so as the refactoring becomes:

int? age2b = explainingVar?.age;

And hence ?. could be used on nullable type to mean if the nullable type is null, return null, otherwise call/get the member on the Value of the nullable type
Coordinator
Apr 8, 2014 at 1:44 AM
Edited Apr 8, 2014 at 3:22 AM
Olmo wrote:
ljw1004, it's written up ...
Okay, so writing it out in full...
1 = left-associative / trivial-polluter
2 = right-associative / complex-clean
3 = optimized lambda
// I want to do null-checks on GetCustomer1(), and on extraRef, and on name
1: var x = GetCustomer1()?.extraRef?.name?.Length;
2: var x = GetCustomer1()?.extraRef?.name?.Length;
3: var x = GetCustomer1().Try(c => c.extraRef).Try(r => r.name).Try(n => n.Length);

// I want to do null-checks on GetCustomer1(), but skip them on extraRef and on name
1: var x = GetCustomer1()???? *impossible*
2: var x = GetCustomer1()?.extraRef.name.Length;
3: var x = GetCustomer1()?.Try(c => c.extraRef.name.Length);
Is that right?
Apr 8, 2014 at 7:14 AM
Edited Apr 8, 2014 at 7:16 AM
lwischik, it's not really about what you want to do as a developer, but about how they will design the feature.

Let's imagine imagine that we were using only structs and nullable struct here, so we're able to reason about types:

1.- left-associative / trivial-polluter

Every time we have a T?, and T has a member (or method) returning P, we can use .? operator to get a P?
GetCustomer1()   //returns Customer?

GetCustomer1()?.extraRef  // is a ExtraRef?, even if the propery is of type ExtraRef
GetCustomer1()?.extraRef?.name //is a string?, even if the property is of type string 
GetCustomer1()?.extraRef?.name?.Length //is a  int?, even if the property is of type int 
GetCustomer1()?.extraRef?.name?.Length == 1//compares int? and int, returning a boolean
The implementation is trivial, but once you start using ?. in a chain, you have to use it till the end, polluting the rest of the line. Is kind of similar to Haskell IO<T>

If we compare this behavior with my Try method, it will be like this:
GetCustomer1()   //returns Customer?

GetCustomer1().Try(c=>c.extraRef)
GetCustomer1().Try(c=>c.extraRef).Try(er=>er.name) 
GetCustomer1().Try(c=>c.extraRef).Try(er=>er.name).Try(n=>n.Length)
GetCustomer1().Try(c=>c.extraRef).Try(er=>er.name).Try(n=>n.Length) == 1 //The expansions stops here because there are no more ?. operators
2.- right-associative / complex-clean
GetCustomer1()   //returns Customer?

GetCustomer1()?.extraRef  
// Is a ExtraRef?, except if the following expression also contains a . or .? operator, that will be considered of type ExtraRef.
// Since the next expression is going to be a . operator (name), it will be considered of type ExtraRef

GetCustomer1()?.extraRef.name 
// Is a string?, except if the following expression also contains a . or .? operator,  that will be considered of type string
// Since the next expression is going to be a . operator (Length), it will be considered of type ExtraRef

GetCustomer1()?.extraRef?.name?.Length 
// Is a int?, except if the following expression also contains a . or .? operator,  that will be considered of type string
// Since this time is not the case, the final type of the expression is int?

GetCustomer1()?.extraRef?.name?.Length == 1 
//compares int? and int, returning a bool
The trick here is that there's a hidden lambda, that gets larger every time you use a dot but not for any other operator. The result is clean but is complex to understand.

This is how it will compare with Try method.
GetCustomer1()   //returns Customer?

GetCustomer1().Try(c=>c.extraRef)
GetCustomer1().Try(c=>c.extraRef.name) 
GetCustomer1().Try(c=>c.extraRef.name.Length)
GetCustomer1().Try(c=>c.extraRef.name.Length) == 1 //The expansions stops here because there are no more ./?. operators
Notice how the behavior is much clearer using Try method, because we know there the magic ends: when you close the parenthesis.

Notice also, how the Try method is more expressive because you can write:
GetCustomer1().Try(c=>c.extraRef.name.Length == 1) 
//returns bool? that will be
//if GetCustomer1()is null, returns null
//else if name.length  is 1, returns true 
//         else returns false
I think, after many explanation, we can agree that this feature is way to complex and case-specific for being implemented

Let's just:
  • Add Try method in the BCL, maybe with another name like NullOr of you prefer.
  • Teach the C# compiler to, for any method named Try that takes a lambda, avoid compiling the lambda all together and translate it to inline conditionals instead.
  • Simplify the lambda syntax so we can write
GetCustomer1().Try(@.extraRef.name.Length == 1) 
as proposed here https://roslyn.codeplex.com/discussions/541330
Apr 8, 2014 at 7:42 AM
This might be a little confusing for delevopers, but why not support both?
    a?.b // left-associative
    a.?b // right-associative
Apr 8, 2014 at 8:52 AM
An interesting idea. But two complex things don't make a simple one.
Apr 8, 2014 at 10:37 AM
As an aside, Olmo did not answer ljw1004’s question:
Olmo, how would you write the "Try" method version when name might be null as well and so needs its own null-check?
The answer is:
GetCustomer1().Try(c => c.extraRef.name.Try(n => n.Length))
Apr 8, 2014 at 10:41 AM
The design guidelines for extension methods are that they should not accept null values for the extended object (in fact extension methods are used to extend objects of some type and not the type itself) because a method with the same signature might be added to the type in the future causing a NullReferenceException to be thrown.

Adding a Try (or NullOr or whatever) extension method to the BCL would require explicit namespace importing or explicit class reference if a Try method was added to the type of the object we are "trying".

I like right associative because it might be a developer's decision that not all parts of the chain can be nullable. I might wan to write persion?.Name.FirstName.Lengh because if person is not null, if Name or Name.FirstName something very bad happened. But, in the end, the result will always be of type int?.

And this needs to be refactorable. It's not hard, but the result is not what you would expect.
var l = persion?.Name.FirstName.Lengh
can be refactored into:
var n = person?.Name;
var fn = n?.FirstName;
int? l = fn?.Length
which is do not mean the same because Name and FirstName can now be null.
Apr 8, 2014 at 10:56 AM
The design guidelines for extension methods are that they should not accept null values for the extended object (in fact extension methods are used to extend objects of some type and not the type itself) because a method with the same signature might be added to the type in the future causing a NullReferenceException to be thrown.
Yup, it will break the guidelines.
Adding a Try (or NullOr or whatever) extension method to the BCL would require explicit namespace importing or explicit class reference if a Try method was added to the type of the object we are "trying".
Good point but also applicable to all LINQ. Someone could have had a Select, Where, etc.. method before.

In this case the instance method should be used, of course.
Apr 8, 2014 at 11:02 AM
Olmo wrote:
Good point but also applicable to all LINQ. Someone could have had a Select, Where, etc.. method before.
Someone could and can add any of the LINQ operators to types. As long as the signature and semantics are the same, the compiler will favor the instance methods over any extension method.

But LINQ operators don't extend null as Try would.
Apr 8, 2014 at 11:03 AM
Edited Apr 8, 2014 at 11:33 AM
Olmo wrote:
The method takes advantage that you can call extension methods on null values.
This is a design flaw being exploited rather than an advantage.

Olmo wrote:
The design guidelines for extension methods are that they should not accept null values for the extended object (in fact extension methods are used to extend objects of some type and not the type itself) because a method with the same signature might be added to the type in the future causing a NullReferenceException to be thrown.
Yup, it will break the guidelines.
Please, don't! Guidelines are there not to be broken. Your Try method can already be implementing using the Maybe monad approach (I changed the name to reflect the intent - checking for nulls):
If.NotNull(GetCustomer1()).NotNull(c=>c.extraRef).NotNull(er=>er.name).Get(n=>n.Length)
It follows the pattern of other .NET Framework libraries:
Parallel.For(...)...
Task.Start(...)...
Enumerable.Range(...)...
Olmo wrote:
Teach the C# compiler to, for any method named Try that takes a lambda, avoid compiling the lambda all together and translate it to inline conditionals instead.
Did anyone do this sort of thing in any language ever (treating methods differently based on names)? It sounds like mixing the language and libraries. What about code that already has Try extension methods?

PS: most definitely would not use TryCC, TryCS... naming pattern. There are two general kinds of types in .NET Framework: reference and value types. My personal preference is to use NotNull(...).Get(...) for reference values and NotNull(...).GetVal(...) for value types.
Apr 8, 2014 at 11:18 AM
The alternative is that someone have to come here and spend 3 hours trying to understand what the hell ?. does, for finally realizing that it's a partial ad-hoc feature.

It's just too complicated.

Another problem:
string str = null;

str?.Length //type int?
str?.Length.Value  //type int?
str?.Length.Value.Value  //type int?
...
str?.Length.Value.Value.Value.Value.Value.Value   //aaaaaaaaargggh! 
Of course is solvable but I can feel the frustration.
Apr 8, 2014 at 11:24 AM
Nope!

Because:
string str = null;
int? l = str?.Length;
bool hv = l.HasValue;
int v = l.Value;
Nullable value types have special treatment in other parts of the language and CLR. the same will happen here.

But you could write:
str?.Length?.Value?.Value?.Value?.Value?.Value?.Value
Apr 8, 2014 at 11:30 AM
Another special case, as if this feature didn't have enough already!

And, the type of the expression str?.Length?.Value is definitely typed to int after your special case, how are you going to write ?. after that? Another special case?
Apr 8, 2014 at 11:47 AM
Also:
string str = null;

str?.Length //type int?
If the user hovers with the mouse over Length property the type will stand for int? but when he press . what the auto-complete should show?
  • int members
  • int? members
  • a mixture of both
Apr 8, 2014 at 11:56 AM
That's not a special case for this feature. It's a normal special case for nullable value types.

And, come to think of that, you couldn't do what I said you could.
Apr 8, 2014 at 11:58 AM
Intellisense is context sensitive. In this context, the type of the resulting expression is int?.
Apr 8, 2014 at 12:09 PM

str?.Length.Value.Value 

That's not possible with either left or right associativity.

With left associativity, the str?.Length is a nullable int. You could then call .Value on it, but it ends there.

With right associativity you wouldn't be allowed the .Value: you'd have to end the right associativity with parenthesis, eg:
(str?.Length).Value
Again, it ends there.
Apr 8, 2014 at 12:13 PM
I would allow ?. operator to be usable only on reference types on the left. Using it on nullable value types like int? is almost useless, leading to confusion of the type.
Apr 8, 2014 at 12:23 PM
pazucha wrote:
I would allow ?. operator to be usable only on reference types on the left. Using it on nullable value types like int? is almost useless, leading to confusion of the type.
So how would you deal with Customer.Location.Longitude where Location is a Nullable type ?
Apr 8, 2014 at 12:38 PM
BillMcC,
Again, it ends there.
You're right, I confused the behavior.

But the fact that I confused it, after 1 day of discussion, makes it clear that the feature is quite hard to grasp.

What a trick! Winning the argument by loosing it :)
Apr 8, 2014 at 12:55 PM
Edited Apr 8, 2014 at 1:11 PM
There's still the Intellisense issue:
Customer?.DateOfBirth

What Intellisense should indicate when you hover DateOfBirth?

1.- That it's a DateTime

Because you can continue doing
Customer?.DateOfBirth.Year
2.- That it's a DateTime?

Because you can continue doing
Customer?.DateOfBirth.Value
because a var will infer DateTime?
var date = Customer?.DateOfBirth
And because it will be added to TimeSpan with null propagation semantics, returning, again, DateTime?
Customer?.DateOfBirth + new TimeSpan(2, 0, 0)

And what Intellisense should show when you write the next dot?

  • DateTime Members (Year, Month...)
  • DateTime? Members (Value and HasValue)
  • a mixture of both
Apr 8, 2014 at 12:56 PM
Olmo wrote:
But the fact that I confused it, after 1 day of discussion, makes it clear that the feature is quite hard to grasp.
It is tricky to discuss alternatives: a prime example is even Lucian confused some of his first examples. I feel I have a good grasp of the concepts, but I too get confused when there are different alternatives suggested, especially if they have different "quirks" about them. But if there was only one implementation, then the discussion would just be about the behaviour, and any misunderstandings quickly cleared up.
The way I try to look at it is if we were to have the one behaviour, what would be the questions developers would ask once it has been implemented. With right associativity, I think it is reasonably intuitive: I'd only expect questions about the use of parenthesis etc. With left associativity I'd expect ot see questions about why I need to have ? throughout the expression, and why couldn't I skip the null checks where I didn't want them.
Apr 8, 2014 at 1:10 PM
Olmo wrote:
There's still the Intellisense issue:
Customer?.DateOfBirth

What the Intellisense should do when you hover?

Depends on which associativity you pick.

With Left you cannot write:
Customer?.DateOfBirth.Year
You could write Customer?.DateOfBirth.Value.Year but that would be pointless as it would still throw a null exception if Customer is null because Customer?.DateOfBirth would be null.
So for Left associativity the only valid syntax would have to be Customer?.DateOfBirth?.Year In this case the second ?. is on a nullable datetime, and works like I suggested earlier: if the nullable is null it returns null otherwise it implicitly gets the Value and calls the member on the Value, in this case: Year.

With Right associativity, you can write:
Customer?.DateOfBirth.Year
It returns an int? There is no null checking on DateOfBirth, only on Customer
If you wanted to you could force a nullable datetime by using parenthesis, eg
(Customer?.DateOfBirth)?.Year
Apr 8, 2014 at 2:01 PM
it's DateTime. Only the last part is the nullable part.

This assuming you are talking about right-associative. Otherwise it wouldn't even compile.
Apr 8, 2014 at 2:32 PM
BillMcC and BillMcC:

I was assuming right-associativity (complex-clean).

So it's a DateTime, but
  1. Can you write .Value (or .HasValue) just after it?
  2. Will show .Value (or .HasValue) in the intellisense before you do it?
Also, in this example:
var myDate = Customer?.DateOfBirth; 
3.- If you hover DateOfBirth is a DateTime, but if you hover var will be a DateTime?.

I think the only reasonable choice is that, when you hover, the indicated type will be DateTime? with the question mark semi-transparent (gray) because actually is in between.

Similarly the Intellisense should show the union of the DateTime members (Year, Month...) and DateTime? members (Value, HasValue).

Assuming this choices, another interesting question...

What will we do if DateTime had a Value (or HasValue) property?
Apr 8, 2014 at 2:41 PM
  1. No, you need o use parenthesis as per my previous post if you want to surface the nullable (terminate the right associativity)
  2. No, as above.
  3. Vary will be DateTime? as it is the result of checking for null in the expression

Apr 8, 2014 at 3:27 PM
Edited Apr 8, 2014 at 3:29 PM
Nice answers, I like it.

Final comment: I've just written a code similar to this (not an example):
string message = contact.LastReception
           .Try(lr => lr.EndDate.Try(dt => dt.ToAgoString()) ?? "In progress...")
Without Try, and using ?. instead will be:
string message = contact.LastReception == null ? null :  
           (contact.EndDate?.ToAgoString()) ?? "In progress..."))
But nothing stops me from using Try and ?. together:
string message = contact.LastReception
           .Try(lr => contact.EndDate?.ToAgoString() ?? "In progress...")
Apr 8, 2014 at 4:37 PM
I’m not sure why the issue of .Value and the type of the expression is contentious, but here’s how it works, very simply:

If you type
customer?.DateOfBirth.
                     ↑ triggers IntelliSense
the behaviour is equivalent to typing the . in this location:
customer.Try(c => c.DateOfBirth. )
                               ↑ triggers IntelliSense
Clearly, the type at this location is non-nullable DateTime, so the IntelliSense must list (and the compiler must accept) only the members of that. That includes .Day etc., but not .Value, nor ?..

If you type
(customer?.DateOfBirth).
                       ↑ triggers IntelliSense
the behaviour is equivalent to typing the . in this location:
customer.Try(c => c.DateOfBirth).
                                ↑ triggers IntelliSense
Clearly, the type is nullable DateTime?, which means IntelliSense lists (and the compiler accepts) .Value as well as ?., but not .Day.

In neither case is there any overlap or ambiguity as to what set of members is allowed or listed.
Apr 8, 2014 at 7:58 PM
Hi Timwi,

Nice explanation of the behavior! I think now should be clear the expected tooling behavior.

I think we have reached now a reasoned consensus about how the behavior should be:
  1. The ?. operator should be right-associative (complex-clean), because it promotes better coder style and more efficient code by not contaminating the rest of the chain.
  2. Thanks to this decision, ?. should be used only on the optional values: reference types and nullable structs, but not over normal structs (or a possible future non-nullable reference types).
  3. The return type of the operator should be nullified for structs (or non-non-nullified for a future non-nullable reference types). This change in type it's only visible once the chain is broken due to parenthesis or any other operator with a different precedence.
  4. The operator should evaluate the left expression just once, test for nullability, and if not-null evaluate the right side with the cached value. So
order.Customer?.DateOfBirth.Year

//will compile to
var c = order.Customer;
c == null? (int?)null : c.DateOfBirth.Year;

//or using the new declaration expressions
(var c = order.Customer) == null ? null : c.DateOfBirth.Year;
  1. The operator makes a distinction between using an extension method as an extension, or as an static method.
peter?.Cars.Where(c => c.IsElectric)
//Compiles to 
peter == null ? null : 
     peter.Cars.Where(c => c.IsElectric)   // returns null

Enumerable.Where(peter?.Cars, c => c.IsElectric)
//Compiles to 
Enumerable.Where(peter == null ? null :  peter.Cars, c => c.IsElectric)   // throws exception
  1. The AST, at least from System.Expression, should make use a anonymous ParameterExpression that represents the cached value to avoid duplication of MemberExpression and MethodCallExpression. With the following structure
NullMemberExpression( 
   Expression leftExpression, 
   ParameterExpression parameter,
   Expression rightExpression)
An example
order.Customer?.DateOfBirth.Year + 1

var c = ParameterExpression()

BinaryExpression(+,
    NullMemberExpression(
         MemberExpression(
              ConstantExpression(order),
              PropertyInfo("Customer")),
         c,
         MemberExpression(
              MemberExpression(
                  c,
                  PropertyInfo("DateOfBirth")),     
              PropertyInfo("Year")),
     ConstantExpression(1))
Case is closed?

I will love to hear more opinions about non-nullable reference types from this nullability-trained brains here: https://roslyn.codeplex.com/discussions/541334
Apr 8, 2014 at 10:59 PM
Olmo wrote:
  1. The AST, at least from System.Expression, should make use a anonymous ParameterExpression that represents the cached value to avoid duplication of MemberExpression and MethodCallExpression. With the following structure
Olmo, you have clearly explained the "right-associative / complex-clean" approach. It's also my preferred approach. But there are still lots of people who prefer "left-associative / trivial-polluter". I wouldn't call the case closed yet until we hear more from them.


As for the ASTs, I don't think there's need for NullMemberExpression. Let's assume, as in your post, that we're using the new feature "declaration expressions"
order.Customer?.DateOfBirth.Year
==>
(var c = order.Customer) == null ? (int?)null : c.DateOfBirth.Year;
I think everyone would expect declaration-expressions to work with expression-trees, and that people who write LINQ providers will have to deal with them. So, let's just use exactly the same thing to provide expression-trees for ?.
static U NullOr<T, U>(T expr, string member) where T :class where U :class
{
    // var r = (var tmp = expr; tmp==null ? tmp.member : null);
    var param = Expression.Parameter(typeof(T), "expr");
    var tmp = Expression.Variable(typeof(T), "tmp");
    var block = Expression.Block(new[] { tmp },
        Expression.Assign(tmp, param),
        Expression.Condition(
            Expression.Equal(tmp, Expression.Constant(null, typeof(T))),
            Expression.Constant(null, typeof(U)),
            Expression.MakeMemberAccess(tmp, typeof(T).GetMember(member)[0])));
    var lambda = Expression.Lambda<Func<T,U>>(block, new[] { param }).Compile();
    return lambda(expr);
}
Apr 8, 2014 at 11:37 PM
I don't think the c# compiler is going to generate assignments in expression trees:

In .Net 3.0 System.Expression was created to suppor linq to sql, with only expression nodes.
In .Net 4.0 System.Expression was expanded with some language-agnostic statement nodes, but those are not used by the compiler when translating lambada to expressions, are used mainly for dynamic method compilation AFAIK.

AssignmentExpression, even being a expression and not an statement, belongs to the second group.

I think the limitation makes sense, implementing a linq provider is hard, adding variable declaration and assignments will make it almost impossible to translate to sql.

But NullMemberExpression can be easily translated.

Where are those left-associative/trivial-polluter promoters?
Apr 9, 2014 at 8:50 AM
Olmo, I still don't understand exactly your right-associative/complex proposed syntax.
At which kind of construct do you end the 'associativity'? What defines a 'dotchain'?
Consider the following cases.

(A) a?.b.c // c is a field. Translates to "a == null ? null : a.b.c"
(B) a?.b.c // c is a getter. Probably also translates to "a == null ? null : a.b.c"
(C) a?.b.c() // c is an extension method. Does it mean "a == null ? null : a.b.c()" or "c(a == null ? null : a.b)" ?
(D) c(a?.b) // c is an extension method. Does it mean "a == null ? null : c(a.b)" or "c(a == null ? null : a.b)" ?
(E) c(a?.b) // c is a regular method. But we want that to mean "c(a == null ? null : a.b)", right?
(F) a?.b + c // an operator. Also "(a?.b) + c", I think.

Having (A) is the whole point of right-associative/complex. Then (B) seems nice too. But if we have (B), why not (C)? Then it would be surprising to not have (D), right? But (E) would follow, and that is not natural anymore, and we don't want that.
Adding ?. should not cause pain for people who are unaware of the inner workings of the feature, and anywhere you may choose to draw the line, I suppose that there will be cases where it causes surprising behaviour, for example during refactoring.
Apr 9, 2014 at 9:05 AM
Edited Apr 9, 2014 at 9:05 AM
I think the best behavior is:

(A) a?.b.c // c is a field. Translates to "a == null ? null : a.b.c"
(B) a?.b.c // c is a getter. Probably also translates to "a == null ? null : a.b.c"
(C) a?.b.c() // c is an extension method. Does it mean "a == null ? null : a.b.c()" or "c(a == null ? null : a.b)" ?
(D) c(a?.b) // c is an extension method. Does it mean "a == null ? null : c(a.b)" or "c(a == null ? null : a.b)" ?
(E) c(a?.b) // c is a regular method. But we want that to mean "c(a == null ? null : a.b)", right?
(F) a?.b + c // an operator. Also "(a?.b) + c", I think. So it will be (a == null ? null : a.b) + c


the C - D problem is surprising, yes, as I noted:
The operator makes a distinction between using an extension method as an extension, or as an static method.
But I think it's the best choice, the other options is just not to implement the feature
Apr 9, 2014 at 9:48 AM
Olmo, I don't understand why you feel that the left-associative way is not worth being implemented.
I'm the first to agree that the Law of Demeter is far from being universally adopted, but still, most of the time we will just be using a?.b, not a?.b?.c.

The 90% use case is solved perfectly by both left-associative and right-associative proposals.
The 10% use case is not solved well by the left-associative proposal, but it's only sugar, you can still do the right thing manually when it matters.

Solving that 10% case is not worth being surprised at runtime that my code is broken when I only refactored an extension method call from prefix to postfix form.
To me it's more important for such a small-looking syntactic sugar to be immediately and fully understood, than to search for unattainable perfection at the cost of lurking complexity.
Apr 9, 2014 at 10:05 AM
Edited Apr 9, 2014 at 11:10 AM
ljw1004 wrote:
Olmo, you have clearly explained the "right-associative / complex-clean" approach. It's also my preferred approach. But there are still lots of people who prefer "left-associative / trivial-polluter". I wouldn't call the case closed yet until we hear more from them.
In my opinion, left-associative approach is the only possible one because that's how the usual . works. Everyone knows for sure that a.b.c is the same as var temp = a.b; temp.c (purist corner: well, at least for reftype temp). Everyone will see ?. as a variation on . syntax. If ?. would behave in a different way, then adding ? would introduce very subtle, hard to find mistakes.
Apr 9, 2014 at 11:51 AM
Edited Apr 9, 2014 at 1:00 PM
I think one important use case of this feature will be report-like code, where deep chains are bigger:
 Invoice.Customer.Address.Country
We use Try method right now and we usually don't write something like:
 Invoice.Try(i=>i.Customer).Try(c=>c.Address).Try(a=>a.Country) //Very rare
 Invoice.Try(i=>i.Customer.Address.Country) //Common
It's inefficient and looks paranoid, now all the code is going to have a ?. 'just in case' making the root error harder to find.

But its true that trivial-polluter is easier to understand and implement.

Both options have some arguments on their side, if 50% of the people is going to feel disappointed, lets just implement https://roslyn.codeplex.com/discussions/541330
Apr 9, 2014 at 9:22 PM
I think it should be right associative. It doesn't seem that difficult to understand, IMO, and is more useful this way. The minor subtleties with extension methods seem pretty straightforward to understand and shouldn't derail this important feature.
Apr 10, 2014 at 6:50 AM
Edited Apr 10, 2014 at 6:50 AM
I feel that using the right-associative strategy is the best way to go forward, and that it can be consistent. Using the same examples proposed by eldritchconundrum:

(A) a?.b.c // c is a field. Translates to "a == null ? null : a.b.c"
No arguments here, it is the basis of the feature.
(B) a?.b.c // c is a getter. Probably also translates to "a == null ? null : a.b.c"
Also no argument here, any other interpretation still throws.
(C) a?.b.c() // c is an extension method. Does it mean "a == null ? null : a.b.c()" or "c(a == null ? null : a.b)" ?
Here it should mean (a == null ? null : a.b.c()) since it would be consistent with the behaviror of (right-associative) ?. on a normal method (which would throw if called on a null instance).
(D) c(a?.b) // c is an extension method. Does it mean "a == null ? null : c(a.b)" or "c(a == null ? null : a.b)" ?
Should mean c(a == null ? null : a.b). In this case, the developer is explicitly stating that it wants to call the code with the result of the null check. The fact that c is an extension method is not relevant, as in this case it is being used as a normal, static method.
(E) c(a?.b) // c is a regular method. But we want that to mean "c(a == null ? null : a.b)", right?
Clearly if a dev writes this code, its intention is clear. Call the method with the result of the null-check.
(F) a?.b + c // an operator. Also "(a?.b) + c", I think. So it will be (a == null ? null : a.b) + c
Once again, that should be the correct interpretation.
Apr 10, 2014 at 11:16 AM
Member invocation in a member invocation chain is left-associative and the semantics of extension methods is supposed to be the same as instance methods.

Being so, a?.b.c() translates into:
  • a == null ? null : a.b.c() if c is an instance method.
  • a == null ? null : c(a.b) if c is an extension method.
Apr 10, 2014 at 9:37 PM
I haven't thought too much about it yet but would it not just be simpler to have null.whateverer() always compile and return null?
Apr 11, 2014 at 1:17 PM
We have a similar extension method, except that it would accept an expression rather than a lambda:
public static TResult TryGet<T, TResult>(this T obj, Expression<Func<T, TResult>> expression, TResult defaultValue = default(TResult));
The extension method would rewrite the expression to include null checks at various points and to bail with the defaultValue immediately in that case. It was capable of handling expressions like the following:
int? x = obj.TryGet(o => SomeMethod((o.Foo as Bar).Baz));
If o == null or o.Foo == null or (o.Foo as Bar) == null or o.Foo.Baz == null then it would never get to the point of calling SomeMethod.

The primary goal was to easily handle expressions with property member access multiple levels deep. It's also much easier to determine the intent of the developer as the developer would include multiple levels of member access within the expression.

In my opinion, I think that's what the .? operator lacks, the declaration of intent. I think most devs will want to use it in order to access members several levels deep and that if the operator either doesn't enable it or is ambiguous about it without having to study the documentation then it will be a bad experience for those developers.

So, in my opinion, I'd like to see the following behavior (simplified):
  1. var x = a.?b standard use, if a == null then it will return null
  2. var x = a.?b.?c also fine, if a == null or a.b == null then it will return null
  3. var x = a.?b.c compiles, but with a warning, and if a.b == null then attempting to access c will result in a NullReferenceException
  4. var x = a.?(b.c) the same as var x = a.?b.?c
And, yes, I think .?() looks gawdawful, but it establishes the intention of the developer pretty easily.

Just my 2 cents.
Apr 12, 2014 at 12:56 AM
Edited Apr 12, 2014 at 12:59 AM
Halo_Four wrote:
We have a similar extension method, except that it would accept an expression rather than a lambda:
public static TResult TryGet<T, TResult>(this T obj, Expression<Func<T, TResult>> expression, TResult defaultValue = default(TResult));
The extension method would rewrite the expression to include null checks at various points and to bail with the defaultValue immediately in that case. It was capable of handling expressions like the following:
int? x = obj.TryGet(o => SomeMethod((o.Foo as Bar).Baz));
If o == null or o.Foo == null or (o.Foo as Bar) == null or o.Foo.Baz == null then it would never get to the point of calling SomeMethod.

The primary goal was to easily handle expressions with property member access multiple levels deep. It's also much easier to determine the intent of the developer as the developer would include multiple levels of member access within the expression.

In my opinion, I think that's what the .? operator lacks, the declaration of intent. I think most devs will want to use it in order to access members several levels deep and that if the operator either doesn't enable it or is ambiguous about it without having to study the documentation then it will be a bad experience for those developers.

So, in my opinion, I'd like to see the following behavior (simplified):
  1. var x = a.?b standard use, if a == null then it will return null
  2. var x = a.?b.?c also fine, if a == null or a.b == null then it will return null
  3. var x = a.?b.c compiles, but with a warning, and if a.b == null then attempting to access c will result in a NullReferenceException
  4. var x = a.?(b.c) the same as var x = a.?b.?c
And, yes, I think .?() looks gawdawful, but it establishes the intention of the developer pretty easily.

Just my 2 cents.
My issue with this implementation is that using the ?. operator will cause a proliferation of ?. and obscure part of the meaning from someone reading the code. An example:
  1. Lets say I have a.b.c.d where only a and c can be null (either because b and d are a value type or are always assured to have a valid reference)
  2. Using ?. as you propose (left-associative) would mean that I have to write a?.b?.c?.d. Which means that someone reading the code cannot determine only from reading which parts of the expression can return null.
  3. If instead the code were written as a?.b.c?.d (using right-associative ?.), I can gleam from the code that only a or c are expected to be null (key word here is 'expected', the compiler provides no assurances, but the person that wrote the code should know when to expect a null, hence why he uses . instead of ?.).
  4. Furthermore, If the expression returns null, it is either because a == null or c == null (assuming of course that d is never null or is a value type)
  5. Finally I'm assured that no exception will be thrown if either a == null or c == null. On the other hand I will still get an exception if a != null && b == null which is perfect since the code assumes that b != null, so if b is actually null, it is an exceptional condition.
EDIT: Fixed the order of ?. (originally wrote .?)
Apr 12, 2014 at 1:22 AM
carlossarmiento wrote:
My issue with this implementation is that using the ?. operator will cause a proliferation of ?. and obscure part of the meaning from someone reading the code. An example:
  1. Lets say I have a.b.c.d where only a and c can be null (either because b and d are a value type or are always assured to have a valid reference)
  2. Using ?. as you propose (left-associative) would mean that I have to write a?.b?.c?.d. Which means that someone reading the code cannot determine only from reading which parts of the expression can return null.
  3. If instead the code were written as a?.b.c?.d (using right-associative ?.), I can gleam from the code that only a or c are expected to be null (key word here is 'expected', the compiler provides no assurances, but the person that wrote the code should know when to expect a null, hence why he uses . instead of ?.).
  4. Furthermore, If the expression returns null, it is either because a == null or c == null (assuming of course that d is never null or is a value type)
  5. Finally I'm assured that no exception will be thrown if either a == null or c == null. On the other hand I will still get an exception if a != null && b == null which is perfect since the code assumes that b != null, so if b is actually null, it is an exceptional condition.
Left or right associative apart, I totally agree with you. If by design b is supposed to not be null and it is, then something went wrong and I want it to fail.

Most people fail to understand that this is a good design decision.
Apr 12, 2014 at 2:09 AM
Using ?. as you propose (left-associative) would mean that I have to write a?.b?.c?.d. Which means that someone reading the code cannot determine only from reading which parts of the expression can return null.
I prefer whatever is easy to use by the target audience without them having to read the documentation a couple of times and still resulting in accidental NullReferenceExceptions. The extension method I wrote follows more the flow of the right-associative approach which is what I think that I prefer, although I think it's easy to lose that first null-propagating operator in the mix. The addition of parens, while ugly as sin, mixes the approach and gives the developer the capability to declare what they want to happen, each operator itself being left-associative, but the entire body of the parens like right-associative, if that makes sense. I'm not proposing that syntax in any way, I'm just throwing spaghetti at the wall.

Either way, I think that this syntax should be painfully easy to use so that a developer can perform null-propagating single- and multiple-depth member access without having to have a deep understanding how the compiler will parse their expression, and if there is any case in which an expression containing a null-propagation operator may still result in a NullReferenceException that the compiler should emit a warning about it.

It's funny, I discussed this thread with one of the compiler writers of the Oxygene language and they had this very same discussion five years ago when they added the same operator to their language. Perhaps we have room to learn from our neighbors?

Oxygene - The Colon Operator
Apr 13, 2014 at 11:00 AM
@Halo_Four: It is not clear what you are advocating, and it is also not stated on the page you linked to what the associativity of the colon operator in Oxygene is. Perhaps if you could enlighten us?

I, too, prefer whatever is easy to use by the target audience, which includes not getting an unexpected NullReferenceException. This implies that we need it to be right-associative. The left-associative option would cause the “target audience” to either write foo?.BaseStream.Close() and then be surprised to get a NullReferenceException; or to write foo?.BaseStream?.Close() and then potentially spend vastly longer on finding the bug if BaseStream was unexpectedly null, because this code masks that bug. The right-associative design fulfills exactly your criterion: “painfully easy to use [...] without having to have a deep understanding how the compiler will parse their expression”: someone with no deep understanding of the parsing will assume foo?.BaseStream.Close() will not throw if foo is null.
Apr 14, 2014 at 5:49 PM
Edited Apr 14, 2014 at 5:50 PM
  1. var x = a.?b.c compiles, but with a warning, and if a.b == null then attempting to access c will result in a NullReferenceException
If semantics which can be expressed syntactically are potentially useful, it should be possible to express them without any warnings. How should one write code for the case where "a" being null should yield null, and "a" being non-null but "a.b" being null should throw an exception?
  1. var x = a.?(b.c) the same as var x = a.?b.?c
Choice 4 doesn't make a whole lot of sense to me. If one wants a non-exceptional code path when a is non-null but a.b is null, then a.b should have a question mark after it.

Personally, I'd prefer to have ?. be part of a ternary operator with : similar to the ? token (since null is a common default value, but by no means the only plausible one). Because null is a common default, have a means of allowing :null to be elided, at least in cases which would otherwise telescope out to
foo?.bar?.boz?.mum : null : null : null
Alternatively, perhaps have ?. be part of a ternary operator, and foo.?bar be equivalent to `(foo?.bar : null), left-associative and with higher precedence than the ternary form.
Apr 14, 2014 at 7:56 PM
Timwi wrote:
. The right-associative design fulfills exactly your criterion: “painfully easy to use [...] without having to have a deep understanding how the compiler will parse their expression”: someone with no deep understanding of the parsing will assume foo?.BaseStream.Close() will not throw if foo is null.
It would not make sense to have foo?.BaseStream.Close() compile in such a fashion that if foo is null, it would try to invoke null.Close(). I don't think that means the operator should be considered right-associative, however. Rather, it would mean that given a sequence of value dotOp member dotOp member dotOp member (where dotop is either an unconditional or conditional member-access token), the skipping behavior for null references should skip until it sees something other than a member accesses. Right-associativity implies that x op y op z equals x op (y op z), which in turn implies that (y op z) must have a value. While one could modify the language so (.y.z) would have a value, that would have implications beyond associativity.
Apr 16, 2014 at 9:45 AM
supercat wrote:
It would not make sense to have foo?.BaseStream.Close() compile in such a fashion that if foo is null, it would try to invoke null.Close().
Why not?
Having foo?.BaseStream.Close() throw when foo is null, to me, is the expected behaviour.
That's what a dot means, and people know how to use it.

With left-associativity, what makes no sense is writing a?.b.c in the first place. We could simply issue a warning that says: "Either use a?.b?.c, or use a == null ? null : a.b.c, depending on whether you want to throw if a != null && a.b == null."

a == null ? null : a.b.c is not the main use case that the a?.b syntax is trying to solve, a == null ? null : a.b is.
Apr 16, 2014 at 2:14 PM
Yeah, "advocating" is a strong word. I think I understand both sides of the argument and they both have merit.

Oxygene follows left-associative. Command:Caption:Text:Length is equivalent to a?.b?.c?.d, and if you miss a : operator and accidentally put a . operator you may get a NullReferenceException. The reason for this decision was because : is effectively a variant of . and therefore should be interpreted in the same manner. Currently Oxygene does not emit a compiler warning if you mix the two in a manner that could result in a NullReferenceException but it is now being considered.

To me, ?. being left-associative seems technically correct as it does follow the expected rule semantics for the existing . operator.

However, I also think that the target audience of such a language feature (read, not compiler enthusiasts) will intuitively expect that the ?. operator exists to avoid NullReferenceExceptions and won't immediately grasp that proper but mistaken usage of the operator will continue to result in said exceptions.

I think I'm fine with either approach, but in my opinion if the operator is implemented as left-associative then the compiler should emit warnings by default if the user combines ?. and . in the same expression.

The one thing I think being left-associative may make clearer is dealing with value types, whether they are already nullable or are nullable as a result of the previous usage of ?.. If you use the . operator you are working directly against the nullable value type whereas if you use the ?. operator you work on non-nullable value type.

With right-associative I'm not sure that the following will be possible:
bool hasValue = myObject?.MyInt32.HasValue;
To complicate that further, what if the value type actually has a HasValue or Value member of its own? Would that previous code access the member on the value type or on the nullable value type?
public struct MyValueType
{
    public int Value { get; set; }
}

public class MyReferenceType
{
    public MyValueType MyValueType { get; set; }
}

...
MyReferenceType o = null;

var result = o?.MyValueType.Value;  // is result of type MyValueType or of type Nullable<int>?
Apr 16, 2014 at 2:40 PM
Edited Apr 16, 2014 at 2:41 PM
@Halo_Four:

My issue with compiler warnings is that if we have to warn users about a language's feature's behavior then the behavior is counterintuitive (hence the warning). Making the compiler warn that 'expression x might throw NullReferenceException' implies that, for someone who has a basic understanding of ?. the expected behavior is no throwing.

For the case of value-types, I find that it is possible to have an intuitive behavior with right-associative ?.:
With right-associative I'm not sure that the following will be possible:
bool hasValue = myObject?.MyInt32.HasValue;
The return type for the expression would be possible and should be bool?. The reason is quite simple, the operation can return null, true or false. And it is intuitive since we know that ?. will return null if myObject == null. Furthermore, having a third value in this case does not pollute the meaning of the expression. Since it is impossible for HasValue to return null, we know that a null result means that myObject == null and therefore there was never a reference of MyInt32 to consider. This information might come in handy to, for example, fetch myObject from storage and then reevaluate. If on the other hand we receive true or false, we know myObject is valid and know if MyInt32 has a value or not.

Finally in your last example, the return type of the expression o?.MyValueType.Value has to be int?. The reason is that, when o != null the return is an int, which is not convertible to MyValueType, but it is convertible to int?. For the case o == null since the return is null (and null is convertible to Nullable<whatever>) both results are possible. Since at compile time we cannot determine which result we will get, we must go with the most restrictive option.
Apr 16, 2014 at 3:09 PM
So in right-associative you should be able to reference members of both T and Nullable<T>?

In the case that T has either HasValue or Value members that it should assume that the user intended to get to T.HasValue or T.Value rather than Nullable<T>.HasValue or Nullable<T>.Value?

What if the property was actually of a nullable value type?
public struct MyValueType
{
    public int Value { get; set; }
}

public class MyReferenceType
{
    public MyValueType? MyNullableValueType { get; set; }
}

...
MyReferenceType o = null;

// is result of type MyValueType, of type Nullable<MyValueType> or of type Nullable<int>?
var result = o?.MyNullableValueType.Value;  
Apr 16, 2014 at 3:16 PM
Halo_four:

var result = o?.MyValueType.Value;

First off, it is important to understand that isn't a valid left associative syntax. If it was left associative, the first part of the expression would propagate to a Nullable<MyValuetype> and calling Value on that would still cause a null exception at runtime if o is null. So basically having the ?. achieves nothing: you might as well not have it (apart from the potential confusion of which "Value" is called.
With right associative, the code would be the same as if there were no null checks as far as member access goes. That is the Value member being called is on MyValuetype. That's the nice thing about right associative, it doesn't mess with the code: you can replace ?. with . and vice versa and the code is the same as far as member access goes. This makes code maintenance vastly better, you can add ?. where you want and only have to deal with null at the end of the entire expression.

RE:
bool hasValue = myObject?.MyInt32.HasValue

To me that is bad, bad, bad. you couldn't write :
bool hasValue = myObject.MyInt32.HasValue
because MyInt32 is an int.

With right associative: what you would do is enclose the expression in parenthesis, eg:

bool hasValue = (myObject?.MyInt32).HasValue

And that makes it clear that you aren't calling a member on MyInt32 you are calling a member on the result of (myObject?.MyInt32)
Apr 16, 2014 at 3:21 PM
Edited Apr 16, 2014 at 3:22 PM
Halo_Four wrote:
So in right-associative you should be able to reference members of both T and Nullable<T>?

In the case that T has either HasValue or Value members that it should assume that the user intended to get to T.HasValue or T.Value rather than Nullable<T>.HasValue or Nullable<T>.Value?

What if the property was actually of a nullable value type?
public struct MyValueType
{
    public int Value { get; set; }
}

public class MyReferenceType
{
    public MyValueType? MyNullableValueType { get; set; }
}

...
MyReferenceType o = null;

// is result of type MyValueType, of type Nullable<MyValueType> or of type Nullable<int>?
var result = o?.MyNullableValueType.Value;  
Right associative would wrap T in Nullable<T> and that behavior is already defined in c# since it is possible right now to have a struct that has a property HasValue inside a Nullable<T>. If the expression has a return type Nullable<T>, the dev should know that to access any property of the wrapped type he has to go through .Value. This is not different from the way the language behaves right now.

On your second point, if the return type of the expression is a Nullable<T> then there is no need to change the return type, since all possible returns from the expression are covered. In this case, the developer would lose the extra information I mentioned in my previous post (he wouldn't be able to tell wheter o was null or MyNullableValueType was null.
Apr 16, 2014 at 3:31 PM
Halo_Four wrote:
So in right-associative you should be able to reference members of both T and Nullable<T>?

In the case that T has either HasValue or Value members that it should assume that the user intended to get to T.HasValue or T.Value rather than Nullable<T>.HasValue or Nullable<T>.Value?

What if the property was actually of a nullable value type?
public struct MyValueType
{
    public int Value { get; set; }
}

public class MyReferenceType
{
    public MyValueType? MyNullableValueType { get; set; }
}

...
MyReferenceType o = null;

// is result of type MyValueType, of type Nullable<MyValueType> or of type Nullable<int>?
var result = o?.MyNullableValueType.Value;  
result is a nullable<MyValueType>

Logically the expression is : if o is null return null otherwise get MyValueType property which returns a Nullable<MyValueType> and then call the Nullable's Value property returning a MyValueType. So the ?. only adds the "if o is null return null" which is coalesced with the return type of the rest of the expression; hence:
Nullable<MyValueType>
Apr 16, 2014 at 3:47 PM
Ok, so the big difference being that you have no intermediate nullable result when evaluated as right-associative. If a.b returns int then a?.b.HasValue is not legal since int has no HasValue member and to access that member explicitly the developer has to define intent via (a?.b).HasValue.

If the member actually returns a Nullable<T> without applying the ?. would right-associative translate that to T instead?
public struct MyValueType
{
    public int Foo { get; set; }
}

public class MyReferenceType
{
    public MyValueType? MyNullableValueType { get; set; }
}

MyReferenceType o = null;

// which of the following two statements is appropriate/legal?
int? foo1 = o?.MyNullableValueType.Foo;
int? foo2 = o?.MyNullableValueType.Value.Foo;
If the second case, I imagine that the Value member is guaranteed to always succeed?
Apr 16, 2014 at 11:08 PM
carlossarmiento wrote:
Finally in your last example, the return type of the expression o?.MyValueType.Value has to be int?. The reason is that, when o != null the return is an int, which is not convertible to MyValueType, but it is convertible to int?. For the case o == null since the return is null (and null is convertible to Nullable<whatever>) both results are possible. Since at compile time we cannot determine which result we will get, we must go with the most restrictive option.
One side effect of this is that you could write:
o?.MyValueType.Value.Value.Value.Value.Value.Value.Value.Value.Value.Value.Value.Value.Value.Value.Value.Value.Value.Value.Value.Value.Value.Value
Just found it funny.
Apr 17, 2014 at 12:16 AM
PauloMorgado wrote:
carlossarmiento wrote:
Finally in your last example, the return type of the expression o?.MyValueType.Value has to be int?. The reason is that, when o != null the return is an int, which is not convertible to MyValueType, but it is convertible to int?. For the case o == null since the return is null (and null is convertible to Nullable<whatever>) both results are possible. Since at compile time we cannot determine which result we will get, we must go with the most restrictive option.
One side effect of this is that you could write:
o?.MyValueType.Value.Value.Value.Value.Value.Value.Value.Value.Value.Value.Value.Value.Value.Value.Value.Value.Value.Value.Value.Value.Value.Value
Just found it funny.
No you couldn't

With Right associative you'd have to enclose the expression in parenthesis to manifest the int?, e.g:
(o?.MyValueType.Value).Value // which would be of type int. // End of story

With Left associative, I don't think you'd be allowed to have a . in an expression after a ?. because it would make the null check useless as it is meant to propagate. It gets messy with all ?. because then the null does propagate,:
LA: o?.MyValueType?.Value is unclear as to which Value is being called, so you could end up having o?.MyValuetype?.Value?.Value?.Value .... with LA unless special rules are put in place around nullable types, which I think is likely anyway, If you have a null checking syntax on a nullable type, HasValue and Value are superfluous, so you could have a special rule that ?. implies .Value on nullable types.

Still, I think it has the potential to get messy with Left Association due to the null propagation. With Right Associative the problem doesn't exist.
Apr 17, 2014 at 12:21 AM
Halo_Four wrote:
Ok, so the big difference being that you have no intermediate nullable result when evaluated as right-associative. If a.b returns int then a?.b.HasValue is not legal since int has no HasValue member and to access that member explicitly the developer has to define intent via (a?.b).HasValue.

If the member actually returns a Nullable<T> without applying the ?. would right-associative translate that to T instead?
public struct MyValueType
{
    public int Foo { get; set; }
}

public class MyReferenceType
{
    public MyValueType? MyNullableValueType { get; set; }
}

MyReferenceType o = null;

// which of the following two statements is appropriate/legal?
int? foo1 = o?.MyNullableValueType.Foo;
int? foo2 = o?.MyNullableValueType.Value.Foo;
If the second case, I imagine that the Value member is guaranteed to always succeed?
second case, but no, Value is not guaranteed to always succeed: the ?. is only checking o for null. If o is not null, there is no guarantee that MyNullableValueType property is not null. If you wanted it guaranteed against null exception, you'd write:
int? foo2 = o?.MyNullableValueType?.Value.Foo
Apr 17, 2014 at 12:40 AM
BillMcC wrote:
PauloMorgado wrote:
carlossarmiento wrote:
Finally in your last example, the return type of the expression o?.MyValueType.Value has to be int?. The reason is that, when o != null the return is an int, which is not convertible to MyValueType, but it is convertible to int?. For the case o == null since the return is null (and null is convertible to Nullable<whatever>) both results are possible. Since at compile time we cannot determine which result we will get, we must go with the most restrictive option.
One side effect of this is that you could write:
o?.MyValueType.Value.Value.Value.Value.Value.Value.Value.Value.Value.Value.Value.Value.Value.Value.Value.Value.Value.Value.Value.Value.Value.Value
Just found it funny.
No you couldn't

With Right associative you'd have to enclose the expression in parenthesis to manifest the int?, e.g:
(o?.MyValueType.Value).Value // which would be of type int. // End of story

With Left associative, I don't think you'd be allowed to have a . in an expression after a ?. because it would make the null check useless as it is meant to propagate. It gets messy with all ?. because then the null does propagate,:
LA: o?.MyValueType?.Value is unclear as to which Value is being called, so you could end up having o?.MyValuetype?.Value?.Value?.Value .... with LA unless special rules are put in place around nullable types, which I think is likely anyway, If you have a null checking syntax on a nullable type, HasValue and Value are superfluous, so you could have a special rule that ?. implies .Value on nullable types.

Still, I think it has the potential to get messy with Left Association due to the null propagation. With Right Associative the problem doesn't exist.
Thus the could.

My head has been spinning from left to right on this for a long time because I want to start with the notion of being left-associative (as almost everything in C# is) but then it doesn't feel right from usage, usability and understanding points of view.

In the end there should be proper language axioms explaining why it is like it is. But I should be dead simple to the common user (I'm counting of those that don't understand the difference between First and FirstOrDefault - and I'm not bringing in Single).
Apr 17, 2014 at 12:55 AM
BillMcC wrote:
RE:
bool hasValue = myObject?.MyInt32.HasValue

To me that is bad, bad, bad. you couldn't write :
bool hasValue = myObject.MyInt32.HasValue
because MyInt32 is an int.

With right associative: what you would do is enclose the expression in parenthesis, eg:

bool hasValue = (myObject?.MyInt32).HasValue

And that makes it clear that you aren't calling a member on MyInt32 you are calling a member on the result of (myObject?.MyInt32)
That might confuse some people.

The compiler can evaluate the type of the expression and see that it's a Nullable<Int32> and, where not ambiguous, treat it as so. But that would be even more confusing.
Apr 17, 2014 at 1:18 AM
PauloMorgado wrote:
BillMcC wrote:
RE:
bool hasValue = myObject?.MyInt32.HasValue

To me that is bad, bad, bad. you couldn't write :
bool hasValue = myObject.MyInt32.HasValue
because MyInt32 is an int.

With right associative: what you would do is enclose the expression in parenthesis, eg:

bool hasValue = (myObject?.MyInt32).HasValue

And that makes it clear that you aren't calling a member on MyInt32 you are calling a member on the result of (myObject?.MyInt32)
That might confuse some people.

The compiler can evaluate the type of the expression and see that it's a Nullable<Int32> and, where not ambiguous, treat it as so. But that would be even more confusing.
The key here is what the "expression" is. Right associative basically checks for null, returning null if null is encountered, otherwise it proceeds along the expression as usual as per the . syntax. So the null is coalesced with the entire expression: that is you have the possibility of the normal expression as you do today where no nulls are encountered OR the possibility of a null result. right associative does not inject or propagate nulls into the expression.

The above code could have been factored out :

int? value = myObject?.MyInt32
bool hasValue = value.HasValue
Apr 22, 2014 at 9:31 AM
Edited Apr 22, 2014 at 9:33 AM
bool hasValue = (myObject?.MyInt32).HasValue;
I think we should discuss realistic code. The above code is not realistic because it’s equivalent to
bool hasValue = myObject != null;
Apr 22, 2014 at 9:02 PM
Timwi wrote:
bool hasValue = (myObject?.MyInt32).HasValue;
I think we should discuss realistic code. The above code is not realistic because it’s equivalent to
bool hasValue = myObject != null;
At most, it's equivalent to this:
bool hasValue = myObject?.MyInt32 != null;
And there's nothing wrong in writing nullable.HasValue instead of nullable != null which makes it realistic code.
Apr 22, 2014 at 9:21 PM
PauloMorgado wrote:
At most, it's equivalent to this:
bool hasValue = myObject?.MyInt32 != null;
That is still also equivalent to myObject != null. (Assuming MyInt32 is of a non-nullable value type.)
Apr 22, 2014 at 9:28 PM
Edited Apr 22, 2014 at 9:29 PM
Timwi wrote:
PauloMorgado wrote:
At most, it's equivalent to this:
bool hasValue = myObject?.MyInt32 != null;
That is still also equivalent to myObject != null. (Assuming MyInt32 is of a non-nullable value type.)
Nope!

The value of myObject?.MyInt32 is null if myObject is null which makes the value myObject?.MyInt32 != null the same as the value of myObject != null but I wouldn't go as far as saying the expressions themselves are equivalent.

But I'm known for being picky.
Apr 23, 2014 at 5:58 PM
Imagine this scenario:
var name = response.list[0].data.user.name.givenName;
and the developer wants name or null, if it is not contained in the response.

In this case it does not make sense to use a safe operator in only a part of the expression, unless all sequent access are automatically safe.

In my opinion this would be clearer with a new syntax, and not the '?.' operator.

A sample could be:
string name = default (response.list[0].data.user.name.givenName);
var age = default (response.list[0].data.user.age) ?? -1;
int? age = default (response.list[0].data.user.age);
This should be also valid for dynamic objects.
Apr 23, 2014 at 6:25 PM
Edited Apr 23, 2014 at 6:26 PM
@PauloMorgado: We seem to be in agreement. Obviously I know that the two versions do not compile to the same IL. However, they produce the same behaviour in every possible situation; that is, they are observationally equivalent, which is what I mean. Because of that, the unnecessarily elaborate version would hardly be written by any competent programmer.

@jvlppm: I don’t understand the problem you see with ?. in the example you gave. Why couldn’t you simply write this?
var name = response.list[0].data.user?.name.givenName;
This is assuming that the user is the one thing that could be “missing” from the response data. If it’s any other piece, the ?. would simply go in a different place. Of course, I would personally also favour a
var name = response.list?[0].data.user.name.givenName;
to enable safe access to indexers, but the C# team seem to be less than thrilled with that idea.
Apr 23, 2014 at 7:31 PM
@Timwi:
Imagine that response is a dynamic object, mapping to a json object, every part of the expression could be null

The expected behavior is:
var name = response.list?[0].data?.user?.name?.givenName;
And it does not make sense to:
response.list?[0].data?.user.name?.givenName;
unless a rare case where you want an exception to be thrown if (and only if) the user object is null.


By default it is not clear weather the ?. operator is Left-associative or Right-associative,
so by wrapping the entire expression it would be clear what should happen, and that the whole expression is safe.
string name = default (response.list[0].data.user.name.givenName);
Here i'm just reusing the default keyword, but it could be used as follows:
string name = (?response.list[0].data.user.name.givenName);
I'm just listing another possible solution,
and using ?. with every expression does make the job.

And that rare case, where you want to validade only part of the expression, is also covered, with:
(?response.list[0].data.user).name.(?givenName);
Apr 23, 2014 at 7:51 PM
Edited Apr 23, 2014 at 7:55 PM
@jvlppm:
The expected behavior is:
var name = response.list?[0].data?.user?.name?.givenName;
And it does not make sense to:
response.list?[0].data?.user.name?.givenName;
It makes perfect sense to me. What is the problem you’re seeing with it?
unless a rare case where you want an exception to be thrown if (and only if) the user object is null.
Why do you think this case is rare? In the C# world, this is actually the more common case: you do want an error to occur if your code has a bug.
By default it is not clear weather the ?. operator is Left-associative or Right-associative,
Most programmers do not think about that (and many don’t even know what left-/right-associative means) and just want it to work the way they expect, which is the right-associative way. The same is true of ? ... :, ??, && and ||. Did you know that these are right-associative? Did you ever ponder how they would be different (and, in the case of ? ... :, wrong most of the time) if they were left-associative? Probably not; you just use them and they do what you expect. ?. would be in the same camp.
and using ?. with every expression does make the job.
I’m glad we agree on this.
Apr 23, 2014 at 9:31 PM
Timwi wrote:
@jvlppm:
And it does not make sense to:
response.list?[0].data?.user.name?.givenName;
It makes perfect sense to me. What is the problem you’re seeing with it?
If you are expecting an NullReferenceException to be thrown in that expression,
does it make a difference whether the exception is raised at null.user.name or null?.user.name

In other words, acessing:

a?.b?.c.d?.e

The c.d part makes the a?.b?.c safe operators useless, resulting in the same behavior as

a.b.c.d?.e

When a/b/c is null -> The same code would be executed, and a NullReferenceException will be thrown

Timwi wrote:
@jvlppm:
unless a rare case where you want an exception to be thrown if (and only if) the user object is null.
Why do you think this case is rare? In the C# world, this is actually the more common case: you do want an error to occur if your code has a bug.
I mean the code will throw an exception, but there is no difference in avoiding the exception at
a?.b, and then trying to access .c


But the behavior is not the same if extension methods are in the mix, where null.Extension() is allowed

So, it only makes a difference (in having those checks before c.d), if d is an extension method call.

where
static void JavaPrint(this string b)
{
    Console.WriteLine(b ?? "null");
}
and
((string)null).JavaPrint();
is valid, and do not throws an exception.

But this is not intuitive, and I think that when a programmer do

a?.MethodA().MethodB().MethodC()

And expect no exception by calling MethodC (even when MethodB returns null)
But want an exception to be raised if MethodA() returns null

Because he is relying on MethodC being called with null references (it is an extension method)

It is a rare case in my opinion.

Timwi wrote:
@jvlppm:
By default it is not clear weather the ?. operator is Left-associative or Right-associative,
Most programmers do not think about that (and many don’t even know what left-/right-associative means) and just want it to work the way they expect, which is the right-associative way. The same is true of ? ... :, ??, && and ||. Did you know that these are right-associative? Did you ever ponder how they would be different (and, in the case of ? ... :, wrong most of the time) if they were left-associative? Probably not; you just use them and they do what you expect. ?. would be in the same camp.
If the behavior of the operator is clear, what is the point of this topic?
I don't want to offend anyone, and I see the reasons for this thread, and the behavior of the operator is in question,

I don't want to get involved in a battle, my opinion is said, and i'll try not to respond at this thread.
And I'm sorry if my statements are confusing, as my english is far from perfect.
Apr 23, 2014 at 10:35 PM
jvlppm wrote:

Timwi is not expecting a NullReferenceException to be thrown. He's just not expecting that name is ever null. If it is, that's an exceptional occurrence and the correct way to deal with it, since it's a null reference, is to have a NullReferenceException thrown.
Apr 24, 2014 at 6:58 PM
eldritchconundrum wrote:
supercat wrote:
It would not make sense to have foo?.BaseStream.Close() compile in such a fashion that if foo is null, it would try to invoke null.Close().
Why not?
Having foo?.BaseStream.Close() throw when foo is null, to me, is the expected behaviour.
That's what a dot means, and people know how to use it.
Then what's the ?. for?
With left-associativity, what makes no sense is writing a?.b.c in the first place. We could simply issue a warning that says: "Either use a?.b?.c, or use a == null ? null : a.b.c, depending on whether you want to throw if a != null && a.b == null."
There is exactly one sensible thing that a?.b.c could possibly mean: if a is null, skip over all chained member-access operations. You even recognize that as a sensible meaning.
a == null ? null : a.b.c is not the main use case that the a?.b syntax is trying to solve, a == null ? null : a.b is.
Who cares about the "main use case". Excessively narrowly targeting features toward particular use cases impairs languages' general usability.

Also, given the expression a?.b?.c?.d, should the compiler's evaluate it as:
typeOfD eval(typeOfA a)
{
   var b = (a == null) ? null : a.b;
   var c = (b == null) ? null : b.c;
   var d = (d == null) ? null : c.d;
   return d;
}
or
typeOfD eval(typeOfA a)
{
   if (a==null) return null;
   var b = a.b;
   if (b == null) return null;
   var c=b.c;
   if (c == null) return null;
   var d=c.d;
   return d;
}
I would suggest that if a is null, it makes no sense to evaluate any chained member accesses whether or not they use the safe operator. If all other accesses use the safe operator, continuing to evaluate them wouldn't hurt code semantics, but would either waste time, or compel the JITter expend otherwise-unnecessary efforts replacing the chained branches with a direct branch to the inevitable result.

An important principle in language design is (or should be) that semantically-correct code should not have to be syntactically uglier than semantically-incorrect code. If no object's c member should ever return null, then the access of d from from an object's c member should fail if the c member does return null. If one can write code which silently ignores a null c as a?.b?.c?.d but the only way to trap on a null c value would be:
var temp1 = a?b;
typeOfD result = (temp1 != null) ? null : temp1.c.d; // Should throw exception if temp1.c is null
If programmers can write a?b?c.d, they're far more likely to write the correct code than if they can't.

Incidentally, the utility of this concept could be made even greater if there were a way to specify the default value of the expression. Also, the same concepts applicable to member access should be equally applicable to indexers (probably with a ?[ syntax; basically say that if the ? is followed by a member accessing operator or index, that operator will be applied to the left-hand operand.
Apr 25, 2014 at 1:49 AM
Well put, supercat!

Just one thing, there's already a way to specify the default value: the null coalescing operator.

Let's say you want to treat null string references as having 0 length. You can do it in two ways:

Now:
(myString ?? string.Empty).Length
Then:
myString?.Length ?? 0
Apr 25, 2014 at 9:49 AM
@jvlppm, you seem to be assuming the left-associative semantics throughout your entire last post, while we’ve long established that the right-associative semantics is the desirable one. This alone addresses most points you raised. As for extension methods, we addressed that earlier: we established that there is a semantic difference between a?.b.c() and (a?.b).c(), and that the latter is useful only if c() is an extension method that tolerates nulls.

Finally, to address your statement that It is a rare case in my opinion. — this is not a matter of opinion, it is a measurable quantity. We should measure it by looking at our existing code. However, if you presume the left-associative semantics and I presume the right-associative one, then we will be measuring different things and not come to an agreement. As far as I’m concerned, I’m aware of several examples in my code where a?.b.c would be equivalent but shorter and it would make semantic sense (when applying the right-associative semantics). Thus, at least in my body of existing code, it is not at all a rare case.
Apr 25, 2014 at 12:16 PM
Yes, I've noticed after my post that you were assuming a right-associative position, and I also agree that it is the best option.
As for "my opinion", it means that I really have no evidence for that, and it is not my job to collect that kind of data, it means that I'm gessing, and someone else should collect that data, if he wants to know for sure.

My sugestion on using default(a.b.c) instead of a.?b.?c is relevant only when the operator .? is left-associative.
Because after the first .? you are forced to use .? through the rest of the expression,
and with my suggestion it would be clear that, the null is not carried on through the rest of the expression, otherwise it would result in a NullReferenceException in the . operator. Making the expression behave like right-associative in the end, but, it would leave no doubts of what happens when a null is found,
and there would be no left/right associative discussion.

If you think that there is a mistake in my post, please ignore it, since this is not a formal proposition, and I am allowed (at least I think) to say my opinion and make mistakes.
Apr 25, 2014 at 5:45 PM
jvlppm wrote:
...it would leave no doubts of what happens when a null is found,
Would you see any problem with allowing a means of explicitly specifying a default for a chained sequence of "?." and "." which should be used if anything in the chain is null, and requiring that it be specified if the last thing in the chain is a non-nullable value type? Perhaps say that foo?bar : boz would be equivalent to foo != null ? foo.bar : boz, but with the caveat that a ?.member or ?[index] should not appear as the second parameter to ? : operator unless enclosed in parentheses?
Apr 30, 2014 at 1:42 PM
supercat wrote:
eldritchconundrum wrote:
Having foo?.BaseStream.Close() throw when foo is null, to me, is the expected behaviour.
That's what a dot means, and people know how to use it.
Then what's the ?. for?
With left-associativeness, it's meant to be used in a?.b or a?.b?.c, never a?.b.c.
That's why it would make sense to make it a warning.
There is exactly one sensible thing that a?.b.c could possibly mean: if a is null, skip over all chained member-access operations. You even recognize that as a sensible meaning.
I do see the benefits of that meaning. I also see a drawback.
Under right-associativity, we will not be able to refactor a?.b.c() as var x = a?.b; x.c(), and that is somewhat surprising.
Same remark for a?.b.m() and ExtMeth.m(a?.b) not being equivalent (if we use Olmo's answer to my ABCDEF examples).
Should every C# developers have to learn that '?.' does not have the same associativity than '.' before they can correctly do such trivial changes to code that use '?.' ?
Who cares about the "main use case". Excessively narrowly targeting features toward particular use cases impairs languages' general usability.
So is breaking expectations about refactoring... It looks like we cannot have everything.

I wonder what other languages do. I just checked Groovy's similar operator: their a?.b.c throws when a is null, so they seem to agree with you.
Well, maybe I should resign myself to having to be careful around ?. when I refactor my code.
Coordinator
Apr 30, 2014 at 4:28 PM
Edited Apr 30, 2014 at 4:29 PM
eldritchconundrum wrote:
Under right-associativity, we will not be able to refactor a?.b.c() as var x = a?.b; x.c(), and that is somewhat surprising.
Sure you can refactor...
return a?.b.c();

==>

var x = a?.b;
return x?.c();
When refactoring, you just have to introduce an additional null-check. Under right-associative, the null-check could be skipped before refactoring, but after refactoring then you're forced to use it. (Under left-associative, the extra null-check could never be skipped, so it looked the same before and after refactoring).
Apr 30, 2014 at 5:45 PM
I hadn't thought in particular about the refactoring issue you mention, though it actually points I think to a deeper issue which is that I dislike the assumption that foo.bar.boz should always be equivalent to (foo.bar).boz; Rather than regarding as evil anything which violates that assumption [such things already exist], I think it would be better to take the view that it should be possible for connections to exist between the later and earlier parts of an expression. The fact that such connections are rare doesn't mean they should be. In many cases, snapshots are easier to reason about than read-only views, , but read-only views are cheaper to construct and will be equivalent to snapshots if they're abandoned before any change to the underlying data. Given var temp = foo.bar, foo has no way of knowing whether it might be modified while temp is still alive, but given foo.bar.boz, if there were a way foo could know if the only thing done with the value of bar was to access one of its members, or if it could be told when it was used in any other fashion, bar could safely return a read-only view if none of its members persisted reference to themselves.
Coordinator
Apr 30, 2014 at 8:18 PM
Edited May 2, 2014 at 2:04 PM
Thank you for all the discussion, everyone. The C# Language Design Meeting met, reviewed everyone's comments, and agreed with right-associative. Particular thanks to Kathleen who provided slides that helped make the argument.

https://roslyn.codeplex.com/discussions/543895

Image


Interestingly, it was pointed out after the fact that CoffeeScript also uses right-associative... for example http://coffeescript.org/#try:a%3F.b.c%3F.d
Marked as answer by lwischik on 4/30/2014 at 1:18 PM
Sep 19, 2014 at 6:26 PM
I fired up CTP3 to experiment with the null propagating operator feature and noticed something that could potentially be improved.
var val = this?.Foo;
I would expect that since "this" can never be null, this code would either produce a compiler warning or the compiler would simply eschew the null check. There is no warning, and looking at the generated code in ILSpy I see the null check. Admittedly, this is a pretty minor issue.
Sep 19, 2014 at 7:07 PM
MarkPflug wrote:
I would expect that since "this" can never be null, this code would either produce a compiler warning or the compiler would simply eschew the null check. There is no warning, and looking at the generated code in ILSpy I see the null check. Admittedly, this is a pretty minor issue.
For methods of structure types, this cannot be null; for non-virtual methods of class types, however, it can. If class Thing has a method void DoSomething(double x), that is semantically equivalent to static void DoSomething(Thing it, double x), which may be assigned to a delegate of type Action<Thing,double>. If the delegate is called act, then act(foo,bar) will be equivalent to foo.DoSomething(bar), except that invoking the latter when foo is null will result in a call to the method with this being null.
Sep 19, 2014 at 7:23 PM
supercat wrote:
MarkPflug wrote:
I would expect that since "this" can never be null, this code would either produce a compiler warning or the compiler would simply eschew the null check. There is no warning, and looking at the generated code in ILSpy I see the null check. Admittedly, this is a pretty minor issue.
For methods of structure types, this cannot be null; for non-virtual methods of class types, however, it can. If class Thing has a method void DoSomething(double x), that is semantically equivalent to static void DoSomething(Thing it, double x), which may be assigned to a delegate of type Action<Thing,double>. If the delegate is called act, then act(foo,bar) will be equivalent to foo.DoSomething(bar), except that invoking the latter when foo is null will result in a call to the method with this being null.
I don't quite understand how you get that delegate assignment to work? I understand everything that you are saying except how to get the instance member assigned as the delegate for Action<Thing,double>?
I can do:
Thing foo = null;
Action<Double> a = foo.DoSomething;
However, the assignment on the second line throws an ArgumentException: "Delegate to an instance method cannot have null 'this'.". Which seems to be intended to explicitly avoid the scenario that you are describing. Can you show me a full code example that reproduces a null "this"?
Sep 19, 2014 at 7:38 PM
Edited Sep 19, 2014 at 7:40 PM
Nevermind, I figured it out:
Action<Thing> a = (Action<Thing>)Delegate.CreateDelegate(typeof(Action<Thing>), null, typeof(Thing).GetMethod("DoSomething"));
So "this" can be null. Learn something new every day.

Though, I'm surprised that this call to CreateDelegate doesn't throw the same ArgumentException that my previous example threw.
Sep 19, 2014 at 9:17 PM
class Bozo
{
    public string name;
    public void doSomething(double x)
    {
        if (this == null)
            Console.WriteLine("I'm null; x is {0}", x);
        else
            Console.WriteLine("My name is {0} and x is {1}", name, x);
    }
}
... and to test it
    static void testIt()
    {
        Bozo bozo1 = new Bozo(); bozo1.name = "Fred";
        Action<double> act = bozo1.doSomething;
        Action<Bozo, double> bozoActor =
            (Action<Bozo, double>)Delegate.CreateDelegate(typeof(Action<Bozo, double>), act.Method);
        bozoActor(bozo1,1.2);
        bozoActor(null,1.4);
    }
Note that the CreateDelegate call doesn't see a null "this", since it's creating a delegate that will accept this as a parameter. If the method were virtual, calling the delegate would fail because the type of this would be needed to select a method, but for non-virtual methods it isn't needed.

As to the reason things work that way, if languages had been required to use call rather than callvirt when invoking non-virtual instance members, that would have eliminated the need for the syntactically horrible String.IsNullOrEmpty(someString), versus the syntactically cleaner someString.IsNullOrEmpty.
Sep 20, 2014 at 12:42 AM
Edited Sep 20, 2014 at 12:56 AM
supercat wrote:
As to the reason things work that way, if languages had been required to use call rather than callvirt when invoking non-virtual instance members, that would have eliminated the need for the syntactically horrible String.IsNullOrEmpty(someString), versus the syntactically cleaner someString.IsNullOrEmpty.
From what I gather that was an explicit design decision made by the C# and VB.NET teams to always emit the callvirt IL opcode when calling an instance method due to the confusion of the behavior of being able to call methods on null references.

http://blogs.msdn.com/b/ericgu/archive/2008/07/02/why-does-c-always-use-callvirt.aspx

This is explicitly codified into the C# Language Specification under section 7.5.5 "Function member invocation" where if the target "is null, a System.NullReferenceException is thrown and no further steps are executed.".

Up until extension methods it was predictable that foo.Bar() would throw if foo was null regardless of how the method was implemented. The syntax you'd prefer could've been accomplished with extension properties which were cut from a previous release because, if I recall, the syntax was just awful looking. I imagine that it would be trivial to implement what you requested, potentially even just using an attribute to annotate the target method instead of adding any new syntax. But support for it from a consumer point of view would depend on changes made to every .NET-targeting compiler..
Sep 20, 2014 at 3:24 AM
Halo_Four wrote:
From what I gather that was an explicit design decision made by the C# and VB.NET teams to always emit the callvirt IL opcode when calling an instance method due to the confusion of the behavior of being able to call methods on null references.
That is my understanding as well, but the fact that invocation via delegates doesn't do a null check might predate that. Personally, I think there should have been an attribute to specify whether a method should be invokable on null, since there some methods where it makes sense and some where it doesn't.

Actually, what might have been best would have been for C# to have included separate . and -> operators, with the implication that . acts upon a variable and -> acts upon a thing referenced by the variable. Field access would use . for structures and -> for classes; for methods and properties, . would pass this by reference and -> would pass it by value, *regardless of whether it was invoked on a class or struct. Obviously too late now, though.
Sep 20, 2014 at 11:37 AM
supercat wrote:
Halo_Four wrote:
From what I gather that was an explicit design decision made by the C# and VB.NET teams to always emit the callvirt IL opcode when calling an instance method due to the confusion of the behavior of being able to call methods on null references.
That is my understanding as well, but the fact that invocation via delegates doesn't do a null check might predate that. Personally, I think there should have been an attribute to specify whether a method should be invokable on null, since there some methods where it makes sense and some where it doesn't.
Well we're talking about a decision made by the C# compiler team specifically regarding how it would behave on these method invocations. If you construct a delegate and invoke it directly you would be bypassing whatever safeguards/guarantees that the C# compiler attempts to enforce and exploiting the capabilities of the CLR, which of course does support this.
Actually, what might have been best would have been for C# to have included separate . and -> operators, with the implication that . acts upon a variable and -> acts upon a thing referenced by the variable. Field access would use . for structures and -> for classes; for methods and properties, . would pass this by reference and -> would pass it by value, *regardless of whether it was invoked on a class or struct. Obviously too late now, though.
I recall that being another explicit design decision, not to have two kinds of accessor operators for standard use, following languages like Java and Visual Basic (pre-.NET) both of which have the same method invocation behavior. Of course C# does have a -> operator but only to be used explicitly when working with pointers.

I think it's one of those cases where just because something is possible doesn't mean that it should be done, even if there are a few cases where it might produce nicer-looking code.
Sep 22, 2014 at 10:40 PM
Halo_Four wrote:
I recall that being another explicit design decision, not to have two kinds of accessor operators for standard use, following languages like Java and Visual Basic (pre-.NET) both of which have the same method invocation behavior. Of course C# does have a -> operator but only to be used explicitly when working with pointers.
Structures and objects are totally different things in VB6. Since VB.NET did not exist prior to .NET, and structure member access can only be performed on things which are explicitly declared to be structures, a mechanical code parser could easily have converted struct field access to use a different operator from class member access when translating existing code.
I think it's one of those cases where just because something is possible doesn't mean that it should be done, even if there are a few cases where it might produce nicer-looking code.
The reason there should have been a distinction IMHO is not because it would have made "nicer-looking" code, but rather because it would have made clear the distinction between operations which are performed upon a storage location, versus operations which are performed upon some outside object to which a storage location holds a reference. If C# and VB.NET had (for consistency with Java) used . as their equivalent to ->, but had required the use of .: for struct field access or the invocation of methods which accept this as a writable byref, then the expected answers to the two questions below would be clear, even without having to know the types of the variables involved.
someType foo1 = bar1;
otherType foo2 = bar2;
foo1.x = 23; // Does this affect bar1.x?
foo2.:y = 57; // Does this affect bar2.y?
The write to foo1.x would be expected to modify a mutable class object to which bar1 holds or encapsulates a reference, while the write to foo2.:y would be expected to modify the variable foo2 (probably a struct, but potentially a reference to an immutable object), and not affect bar2.

With the above design, it would likely not be possible to have an mutating interface that could be usefully be implemented both by a value type and by an inheritable class, but don't know that there's a real usage case for such things. While there are some cases where mutating interfaces are employed with structure types, most of them involve an effort to optimize foreach and would have (at least in retrospect) been better served by allowing the compiler to duck-type using a name like GetForEachEnumerator [which could be hidden in IntelliSense]. That would allow GetEnumerator to return a class object that implements IEnumerator even if GetForEachEnumerator returned a structure that didn't implement any interface but included Current and MoveNext().
Sep 23, 2014 at 11:29 AM
someType foo1 = bar1;
otherType foo2 = bar2;
foo1.x = 23; // Does this affect bar1.x?
foo2.:y = 57; // Does this affect bar2.y?
Try the following:
  • In Visual Studio, go to Tools → Options
  • In the tree view on the left, under “Environment”, find “Fonts and Colors”
  • In the list labeled “Display items”, find “User Types (Value types)”
  • Set it to a different color.
From now on, classes and structs are colored differently in your code. From now on, you can answer the above questions just by looking at the color of the type. Furthermore, because you can’t help but see the color every time you see the type, you will be far more acutely aware (with no extra effort on your part) which types are value types and which are not.

(For obvious reasons, it is similarly beneficial to also change the color of enum types, interfaces and delegates. However, “User Types (Type parameters)” unfortunately doesn’t work, probably due to a bug.)

I am utterly confused by the fact that Visual Studio has this incredibly useful feature, but doesn’t make use of it by default. Why are the colors set the same by default, ensuring that nobody ever finds out that this feature even exists?
Sep 23, 2014 at 1:32 PM
Colors would help, but the feature I would have liked to have seen would have gone beyond that. Some reference types (like string) try to behave as values, and some value types behave like reference types [they encapsulate the identity of a mutable object, and changes to the object are reflected in the properties of the value type]. Allowing both value types and reference types to define members which accept this as a mutable byref and methods which accept this by value would have allowed the two kinds of things have more consistent behavior (class types would mostly use . members, and value types .: members, but either kind of type could offer either kind of member, and the behavior of each kind of member would be the same whether it was operating on a value type or a reference type. For example, an immutable class which used .: for all its member-access functions could e.g. define an X property as something like:
int X { 
  ref get { return _x; }
  ref put
  { 
    var newValue = (this==null) ? new Thing() : (Thing)Clone();
    newValue._x = value;  // Assume backing field is "private set"
    return newValue;
  }
From a client code perspective, the semantics of myThing.:X = 5; would be equivalent to what they would have been if X was a structure. From a performance standpoint, code which frequently modifies individual members of the type could end up generating an excessive number of short-lived objects, but that is a general limitation with immutable classes anyhow.

My main point is that there is a lot of code which expects to be working with values rather than entities; while .NET languages offer better support for values than does Java, they still often force programs to use reference semantics when value semantics would be more appropriate. Having separate syntax for things that behave with value- and reference semantics would facilitate the appropriate use of each [actually, a third type of semantics would help as well: "neutral" semantics--for things where value and reference semantics would be essentially equivalent].
Sep 23, 2014 at 8:42 PM
Timwi wrote:
I am utterly confused by the fact that Visual Studio has this incredibly useful feature, but doesn’t make use of it by default. Why are the colors set the same by default, ensuring that nobody ever finds out that this feature even exists?
.
+1 for "Colors for structs, enums, delegates and interfaces by default!" we have been using this for some time now, here is the vssettings:

https://raw.githubusercontent.com/signumsoftware/framework/master/Snippets/Signum.Fonts.vssettings
Coordinator
Oct 19, 2014 at 7:01 AM
Timwi wrote:
I am utterly confused by the fact that Visual Studio has this incredibly useful feature, but doesn’t make use of it by default. Why are the colors set the same by default, ensuring that nobody ever finds out that this feature even exists?
:) During the development of VS2012, the C++ language service was completely rewritten. They made the default use different colours for absolutely everything. I filed issues on the team complaining that it looked like fruit salad. I guess other people agreed with me, because they scaled the colors down massively before VS2012 was released.

VS14 will apparently have more customizable colors for VB. (maybe also for C#? I'm not sure). They'll be in the next preview release after CTP4.


-- Lucian Wischik, VB/C# team
Oct 26, 2014 at 9:00 PM
Trying this in VS 14 CTP
Expression<Func<string, string>> func = s => s?.ToString();
I get a compile-time error:
Error   1   An expression tree lambda may not contain a null propagating operator.  c:\users\olmo.signums\Documents\Visual Studio 2012\Projects\ConsoleApplication1\ConsoleApplication1\Program.cs  14  58  ConsoleApplication1
Is this work-in-progress or it won't be allowed in expression trees? I that's the case if find it really disappointing.

Expression trees are commonly used for LINQ providers that are translated to SQL. In there navigation properties are typically used to simplify LEFT OUTER JOINS.

SQL, by default, will always propagate the nullability implicitly. So a query like this:
List<int> ids = orders.Select(o=>o.Customer.Id).ToList();
Even if is statically typed as List<int> for C#, if there are orders without customer SQL will try to return null. Then the LINQ provider has two options.
  • Throw an exception because null doesn't fit into int?, forcing the user to convert the query to:
List<int?> ids = orders.Select(o=>(int?)o.Customer.Id).ToList();
List<int> ids = orders.Where(o=>o.Customer != null).Select(o=>o.Customer.Id).ToList();
  • Just convert the null to default(int) (aka 0), creating misleading results.
The best solution will be to be able to express in C# the SQL behaviour more accurately.
List<int?> ids = orders.Select(o=>o.Customer?.Id).ToList();
Letting the user have their own default value:
List<int> ids = orders.Select(o=>o.Customer?.Id ?? -1).ToList();
In order to do the translation allowing in general member access without duplicating all the possible followings of ?. (MethodCallExpression, MemberExpression, etc... a new NullPropagationExpression will be necessary:
    public class NullPropagationExpression : Expression
    {
        public Expression Object { get; private set; }
        public ParameterExpression MemberAccessParameter { get; private set; }
        public Expression MemberAccessBody { get; private set; }

        public NullPropagationExpression(Expression @object, ParameterExpression parameter, Expression body)
        {
            this.Object = @object;
            this.MemberAccessParameter = parameter;
            this.MemberAccessBody = body;
        }
    }
So if currently this:
Expression<Func<string, string>> func = s => s.ToString();
Is translated to
ParameterExpression s;
Expression<Func<string, string>> func = Expression.Lambda<Func<string, string>>(
    Expression.Call(s = Expression.Parameter(typeof(string), "s"), (MethodInfo)methodof(object.ToString)),
    s);
The using null-propagation:
Expression<Func<string, string>> func2 = s => s?.ToString();
Will be translated to
ParameterExpression s;
ParameterExpression p;
Expression<Func<string, string>> func = Expression.Lambda<Func<string, string>>(
    Expression.NullPropagation(
        @object: s = Expression.Parameter(typeof(string), "s"),
        parameter: p = Expression.Parameter(typeof(string)),
        body: Expression.Call(p, (MethodInfo)methodof(object.ToString))),
    s);
Coordinator
Oct 27, 2014 at 9:47 PM
Olmo, thanks for writing that up.

So far we haven't been adding new features to expression-trees. That was sort of okay for "await" and "dynamic" but I agree that ?. would be more valuable. So would statement-bodied lambdas.

I guess we've always had the concern about whether the new feature should be expressed in terms of existing constructs (so existing expression-tree-parsers would accommodate it fine) or new constructs (in which case all existing parsers would need to be updated, otherwise they'll crash at runtime). Also, the expression-tree work always seemed lower value than the other things we could be doing.

How to move forward? One option is a uservoice item to see if it's a common need that our team should address ourselves. Another option is for the community to work towards an grand overarching design for expression-trees in general, and identify the one small ?. corner of them, and make sure that it's coherent with the over-arching design, and submit a pull-request for it.

-- Lucian, VB/C# team
Oct 28, 2014 at 8:14 AM
Edited Oct 28, 2014 at 8:15 AM
lwischik wrote:
Olmo, thanks for writing that up.

So far we haven't been adding new features to expression-trees. That was sort of okay for "await" and "dynamic" but I agree that ?. would be more valuable. So would statement-bodied lambdas.

I guess we've always had the concern about whether the new feature should be expressed in terms of existing constructs (so existing expression-tree-parsers would accommodate it fine) or new constructs (in which case all existing parsers would need to be updated, otherwise they'll crash at runtime). Also, the expression-tree work always seemed lower value than the other things we could be doing.
The existing parsers will need to update in order to support the new feature. This is no different than just creating a new method that should be considered, like translating string.IsNullOrEmptyOrWhiteSpace to SQL. Still, I prefer it to be translated to conditional expression that not translated at all!
How to move forward? One option is a uservoice item to see if it's a common need that our team should address ourselves. Another option is for the community to work towards an grand overarching design for expression-trees in general, and identify the one small ?. corner of them, and make sure that it's coherent with the over-arching design, and submit a pull-request for it.
As you said, Add "?." operator to C# is already the second more voted request, and I don't think that you need to rise a question in uservoice to make a feature complete.

Specially, asking for expression trees support won't we fair. Expression trees are designed to be hidden for most of the developers (just the ones writing LINQ providers really care about them) but many developers just use them without knowing. I'm sure many people in this 5,439 votes is using Entity Framework and will be surprised that it doesn't work.

As I said before, this feature is important for LINQ providers because it reflects the exact behavior of the database when navigating properties using LEFT JOIN, I understand that adding support for await, dynamic, or general statements if/ for / while... will not pay for itself, but null-propagation is how databases work. It's like not having support for Nullable<T> in the database.

If I try to make the pull-request myself:
  • Is there a chance that if will be shipped in VS 14? or this train is already gone?
  • The dependency from the Roslyn compiler to System.Linq.Expressions.Expression is just duck-typed as usual or is there a strong-name dependency? I will need to call the NullPropagationExpression constructor directly since I can not add a method to Expression class, but if I create a class in the System.Linq.Expressions namespace but my own assembly maybe it will work? I will need that somebody also adds the VisitNullPropagation in ExpressionVisitor, and ExpressionType.
Thanks in advance.
Oct 29, 2014 at 12:30 AM
As I understand, Linq.Expressions is supported by DLR. According to their documentation (https://dlr.codeplex.com/wikipage?title=Docs%20and%20specs&referringTitle=Documentation, https://github.com/IronLanguages/main), if language need to add new Expression node, it can be done by implementing custom type derived from Expression that will implement proper method System.Linq.Expressions.Expression Reduce(), that will provide the same expression with only well-know expressions types.
For NullPropagationExpression it can provide implementation with ConditionalExpression. At least Compile method initially call Reduce, same can do expression provider if it wants - or work with simple NullPropagationExpression.
Oct 29, 2014 at 8:21 AM
I've been thinking about it, and the C# 6 compiler is going to be used with .Net 2.0, 3.0, 3.5, 4.0... none of them will have NullPropagationExpression defined. So maybe translating it to ConditionalExpression is a better approach.
Oct 29, 2014 at 10:01 AM
I'm not convinced this is a major issue. From 3.5 to 4.0 a bunch of new expression types were introduced and the ExpressionVisitor extended.
Oct 29, 2014 at 11:12 AM
Sure, but not in the C# compiler generator. The thing is that there is an scenario of someone writing this in any other version of .Net
ctx.Invoices.Select(i=>i.Customer?.Name).ToList()
And this won't work for anybody using something older than .Net 4.5.3 if we go for NullPropagationExpression. While using ConditionalExpression it will work.
Oct 29, 2014 at 3:59 PM
Edited Oct 30, 2014 at 9:00 AM
Olmo wrote:
Sure, but not in the C# compiler generator. The thing is that there is an scenario of someone writing this in any other version of .Net
ctx.Invoices.Select(i=>i.Customer?.Name).ToList()
And this won't work for anybody using something older than .Net 4.5.3 if we go for NullPropagationExpression. While using ConditionalExpression it will work.
Of course it will work. You only have to create a NullPropagationExpression in your project with the exact same surface (namespace and members) as the compiler expects it. This is the same technique LinqBridge lets you do Linq stuff with C# 5.0 targeting .NET 2.0 which never even heard of expressions.

The problem with ConditionalExpression is that if the left side of a?.b has side effects then it is not a trivial a != null ? a.b : null but rather it would become { var tmp = a; return tmp != null ? tmp.b : null;}. And on the consumer side that would be really hard to determine that this was a null propagation expression originally.
Oct 30, 2014 at 11:33 PM
BachratyGergely wrote:
Olmo wrote:
Sure, but not in the C# compiler generator. The thing is that there is an scenario of someone writing this in any other version of .Net
ctx.Invoices.Select(i=>i.Customer?.Name).ToList()
And this won't work for anybody using something older than .Net 4.5.3 if we go for NullPropagationExpression. While using ConditionalExpression it will work.
Of course it will work. You only have to create a NullPropagationExpression in your project with the exact same surface (namespace and members) as the compiler expects it. This is the same technique LinqBridge lets you do Linq stuff with C# 5.0 targeting .NET 2.0 which never even heard of expressions.
Is not that simple. Even if you're happy with this new expression not being completely integrated (in NodeType, ExpressionVisitor, Expression factory method), you solution will work with duck-typing for the compiler, but not for the libraries that will require it. For example, a project written in .Net 4.5 using EntityFramework and MVC will be interested in using ?. both for LINQ queries end for EditFor fields. They will need to agree in one mocked implementation, maybe available via NuGet?. Looks too much hassle for few value.
The problem with ConditionalExpression is that if the left side of a?.b has side effects then it is not a trivial a != null ? a.b : null but rather it would become { var tmp = a; return tmp != null ? tmp.b : null;}. And on the consumer side that would be really hard to determine that this was a null propagation expression originally.
It will be relatively simple to build a ExpressionVisitor that converts compiled-generated ConditionalExpression to the equivalent NullPropagationExpression. For most of the use cases that is good enough.
Oct 31, 2014 at 12:25 AM
PULL REQUEST

This is my first attempt to make the C# compiler translate ?. to expression trees. It's fully working but I'm sure the code could be improved.

https://roslyn.codeplex.com/SourceControl/network/forks/Olmo/NullPropagationExpresions/contribution/7642
Oct 31, 2014 at 4:52 PM
Olmo wrote:
Is not that simple. Even if you're happy with this new expression not being completely integrated (in NodeType, ExpressionVisitor, Expression factory method), you solution will work with duck-typing for the compiler, but not for the libraries that will require it. For example, a project written in .Net 4.5 using EntityFramework and MVC will be interested in using ?. both for LINQ queries end for EditFor fields. They will need to agree in one mocked implementation, maybe available via NuGet?. Looks too much hassle for few value.
There's already a lot of stuff in Expressions not supported in Entity Framework. E.g. the ternary operator and the if-else statement are both represented by a ConditionalExpression but only the former is handled correctly. Stuff that is aware of this feature certainly has builds that reference the framework implementation, there is no need to agree on anything.
EF never evaluates these expressions. There's no reason to use ?. instead of .. What would be the your use case for MVC?
It will be relatively simple to build a ExpressionVisitor that converts compiled-generated ConditionalExpression to the equivalent NullPropagationExpression. For most of the use cases that is good enough.
The expression visitor would have to drill down into the expression tree every time it sees a ConditionalExpression. This is not really performant and breaks the basic visitor pattern by evaluating much more than just the current expression node and direct properties. Most importantly whenever the generated pattern changes (for any reason) the visitor also has to be updated to recognize both the old pattern and the new pattern since the libraries built with the previous compiler do not change.
It's much more reasonable to add a suitable Reduce() implementation. You can actually implement this in a way it automatically expands to ConditionalExpression when processed by the ExpressionVisitor based on e.g. app supported runtime version.
Nov 1, 2014 at 2:24 PM
BachratyGergely wrote:
Olmo wrote:
Is not that simple. Even if you're happy with this new expression not being completely integrated (in NodeType, ExpressionVisitor, Expression factory method), you solution will work with duck-typing for the compiler, but not for the libraries that will require it. For example, a project written in .Net 4.5 using EntityFramework and MVC will be interested in using ?. both for LINQ queries end for EditFor fields. They will need to agree in one mocked implementation, maybe available via NuGet?. Looks too much hassle for few value.
There's already a lot of stuff in Expressions not supported in Entity Framework. E.g. the ternary operator and the if-else statement are both represented by a ConditionalExpression but only the former is handled correctly. Stuff that is aware of this feature certainly has builds that reference the framework implementation, there is no need to agree on anything.
Currently there's two types of expressions in System.Expressions:
  • Expression that represent expressions: Created in .Net 3.5, they are generated by the C# compiler and expected to be supported by a LINQ provider. This group include Add, And, Call, Lambda and in general everything in ExpressionType enum from value 0 to 45.
  • Expression that represent statements: Created in .Net 4, they are not generated by the C# compiler and not expected to be supported by LINQ providers, but are useful to create dynamic methods and I think they are also used by the DLR. This group include Assign, Block, Goto, Throw, and in general everything in ExpressionType enum from value 46 to 84.
I think ?. should be in the first group, be generated by the compiler and used seamlessly in LINQ providers, just as ?? or ? :.
EF never evaluates these expressions. There's no reason to use ?. instead of .. What would be the your use case for MVC?
Not sure if i understood you. I think it makes sense to make this query using entity framework:
List<int?> ids = ctx.Orders.Select(o=>o.Customer?.Id).ToList();
And also makes sense to create this textbox in MVC:
@Html.TextBoxFor(customer => customer.Address?.City)
It will be relatively simple to build a ExpressionVisitor that converts compiled-generated ConditionalExpression to the equivalent NullPropagationExpression. For most of the use cases that is good enough.
The expression visitor would have to drill down into the expression tree every time it sees a ConditionalExpression. This is not really performant and breaks the basic visitor pattern by evaluating much more than just the current expression node and direct properties. Most importantly whenever the generated pattern changes (for any reason) the visitor also has to be updated to recognize both the old pattern and the new pattern since the libraries built with the previous compiler do not change.
It's much more reasonable to add a suitable Reduce() implementation. You can actually implement this in a way it automatically expands to ConditionalExpression when processed by the ExpressionVisitor based on e.g. app supported runtime version.
If there will be a way to patch all the .Net 3.5/4.0/4.5 out there I'll agree with but making a (duck-type) dependency from the C# compiler to NullPropagationExpression has some nasty consequences that I didn't though in my first proposal:
  • Projects using .Net 4.5.3 could use the feature without problems, because NullPropagationExpression will be defined.
  • Projects using any older framework will have to create their own System.Linq.Expressions.NullPropagationExpression class, here the problems start:
    • A library (like EntityFramework) will have to create his own class, but what if another library (like ASP.Net MVC) also wants to use the feature? They will create another System.Linq.Expressions.NullPropagationExpression in a different assembly. How will then the C# compiler know which class to instantiate?.
    • There could be a official Nuget package for that. Bit is this worth just for one class? And I think there could still be issues with libraries that could be used in 4.5.0/1/2/3 at the same time, because the 4.5.3 will already include the class.
Still, even if .Net 4.5.3 will be the only supported Framework, by using ConditionExpression all the LINQ providers that already support ?: will support ?. from day one, maybe generating some additional CASE in SQL, or evaluating the property twice, but it will work. Then the next version could do some optimizations by recognizing the pattern.

I've build a simple project that recognizes the ConditionExpression and translates them to an internal NullPropagationExpression.

https://github.com/olmobrutall/NullPropagation/tree/master/NullPropagation

The code is not trivial and requires ExpressionComparer but is just one step more in the many that LINQ providers have to do already in order to translate to the target language (SQL for example).
Nov 1, 2014 at 9:20 PM
Edited Nov 1, 2014 at 9:21 PM
Olmo wrote:
Currently there's two types of expressions in System.Expressions:
  • Expression that represent expressions: Created in .Net 3.5, they are generated by the C# compiler and expected to be supported by a LINQ provider. This group include Add, And, Call, Lambda and in general everything in ExpressionType enum from value 0 to 45.
  • Expression that represent statements: Created in .Net 4, they are not generated by the C# compiler and not expected to be supported by LINQ providers, but are useful to create dynamic methods and I think they are also used by the DLR. This group include Assign, Block, Goto, Throw, and in general everything in ExpressionType enum from value 46 to 84.
I think ?. should be in the first group, be generated by the compiler and used seamlessly in LINQ providers, just as ?? or ? :.
Right now the compiler generates statements for ?.: extracting the left part to a temporary variable. To do the exact same with non-statement expressions only (without adding/extending expression types) you would get something like a.b?.c.d => new[] { a.b }.Select(t => t.c.d).DefaultIfEmpty(). AFAIK EF does not allow new-array expressions so this would break anyway. Do you have a better pattern in mind?
?? and ?: are not expanded to anything and have their dedicated expression classes. ?? is a BinaryExpression with ExpressionType.Coalesce and ?: is a ConditionalExpression with ExpressionType.Conditional and a non-void return type (if the return type is void then it's an if-statement).
Not sure if i understood you. I think it makes sense to make this query using entity framework:
List<int?> ids = ctx.Orders.Select(o=>o.Customer?.Id).ToList();
EF already treats . as ?. semantically. This is a consequence of pretty much all SQL implementations doing null-propagation and unfortunate since it deviates from the IQeryable contract, but implementing it "right" would be both hard and slow.
The only thing missing is inferring a nullable type for materialization. So the above is the same as
ctx.Orders.Select(o => (int?)o.Customer.Id).ToList();
If Id were already a nullable type (e.g. string) then there would be absolutely no difference between o.Customer.Id and o.Customer?.Id. That is for EF6. There might be changes with null handling in EF7.
And also makes sense to create this textbox in MVC:
@Html.TextBoxFor(customer => customer.Address?.City)
As far as I know MVC helpers do not support conditional expressions in html helpers at all. There would be no point in translating ?. to ConditionalExpression since it would throw the following InvalidOperationExpression: "Templates can be used only with field access, property access, single-dimension array index, or single-parameter custom indexer expressions."
Since MVC is never the producer of such expressions it would only need to consume other implementations, and it can do that without binding to a concrete type.
How would model binding work? Let's assume you put this on a form with Address being null and post it as is, without changing any fields. What would be the result? Should the model binder create an Address object? Then the result would not be the same that was passed to the view. Should it keep the Address property as null? How should it detect from the posted form whether the Address entity should be created or not?
If there will be a way to patch all the .Net 3.5/4.0/4.5 out there I'll agree with but making a (duck-type) dependency from the C# compiler to NullPropagationExpression has some nasty consequences that I didn't though in my first proposal:
  • Projects using .Net 4.5.3 could use the feature without problems, because NullPropagationExpression will be defined.
  • Projects using any older framework will have to create their own System.Linq.Expressions.NullPropagationExpression class, here the problems start:
    • A library (like EntityFramework) will have to create his own class, but what if another library (like ASP.Net MVC) also wants to use the feature? They will create another System.Linq.Expressions.NullPropagationExpression in a different assembly. How will then the C# compiler know which class to instantiate?.
    • There could be a official Nuget package for that. Bit is this worth just for one class? And I think there could still be issues with libraries that could be used in 4.5.0/1/2/3 at the same time, because the 4.5.3 will already include the class.
The entire LINQ language feature, async and dynamic support are all implemented by a "duck-type" dependency from the C# compiler to the framework libraries and they depend on much more than just a single class. The caller member attributes are implemented with the same technique. Using these features already have the exact same problems and the exact same solutions as would upgrading the Expression API. Async does have a dedicated nuget package though much more restricted than the 4.5 implementation due to some supporting things missing from the older frameworks.
Still, even if .Net 4.5.3 will be the only supported Framework, by using ConditionExpression all the LINQ providers that already support ?: will support ?. from day one, maybe generating some additional CASE in SQL, or evaluating the property twice, but it will work. Then the next version could do some optimizations by recognizing the pattern.
I've build a simple project that recognizes the ConditionExpression and translates them to an internal NullPropagationExpression.

https://github.com/olmobrutall/NullPropagation/tree/master/NullPropagation

The code is not trivial and requires ExpressionComparer but is just one step more in the many that LINQ providers have to do already in order to translate to the target language (SQL for example).
Based on your code you seem to assume a.b?.c.d should be translated to a.b != null ? a.b.c.d : null. This is not the pattern and semantics used by the current compiler. What you propose makes (Func)a => a.b?.c.d and ((Expression)a => a.b?.c.d).Compile() behave differently which would be unexpected by most coders. Also for chained null-propagations the number of evaluations per property grows exponentially, e.g. in a?.b?.c?.d c is evaluated 2 times, b 4 times, a 8 times.
Don't forget to implement method invoke (?.Foo(...)) and array element access (?[...]).
Nov 2, 2014 at 9:11 AM
BachratyGergely wrote:
Olmo wrote:
...
Right now the compiler generates statements for ?.: extracting the left part to a temporary variable. To do the exact same with non-statement expressions only (without adding/extending expression types) you would get something like a.b?.c.d => new[] { a.b }.Select(t => t.c.d).DefaultIfEmpty(). AFAIK EF does not allow new-array expressions so this would break anyway. Do you have a better pattern in mind?
?? and ?: are not expanded to anything and have their dedicated expression classes. ?? is a BinaryExpression with ExpressionType.Coalesce and ?: is a ConditionalExpression with ExpressionType.Conditional and a non-void return type (if the return type is void then it's an if-statement).
If evaluating the left part once is mandatory, I will gravitate back to create a new NullPropagationExpression. That's the best solution moving forward but will be harder to use in projects using .Net Framework less or equal than 4.5.3.
Not sure if i understood you. I think it makes sense to make this query using entity framework:
List<int?> ids = ctx.Orders.Select(o=>o.Customer?.Id).ToList();
EF already treats . as ?. semantically. This is a consequence of pretty much all SQL implementations doing null-propagation and unfortunate since it deviates from the IQeryable contract, but implementing it "right" would be both hard and slow.
The only thing missing is inferring a nullable type for materialization. So the above is the same as
ctx.Orders.Select(o => (int?)o.Customer.Id).ToList();
If Id were already a nullable type (e.g. string) then there would be absolutely no difference between o.Customer.Id and o.Customer?.Id. That is for EF6. There might be changes with null handling in EF7.
I completely agree, and I tried to explain it in: https://roslyn.codeplex.com/discussions/571077.

I'm still not happy with the current status-quo for value types: It's a counter-intuitive problem (default null propagation) with a counter-intuitive solution (casting an int to int? produces a null value). With ?. in expressions at least the solution will make sense to a developer.
And also makes sense to create this textbox in MVC:
@Html.TextBoxFor(customer => customer.Address?.City)
As far as I know MVC helpers do not support conditional expressions in html helpers at all. There would be no point in translating ?. to ConditionalExpression since it would throw the following InvalidOperationExpression: "Templates can be used only with field access, property access, single-dimension array index, or single-parameter custom indexer expressions."
I think when designing a language we also have to consider the scenarios that it will enable, not what is possible with the current libraries. Adding support for it shouldn't be hard for the MVC tem.
Since MVC is never the producer of such expressions it would only need to consume other implementations, and it can do that without binding to a concrete type.
Like using reflection to access NullPropagationExpression you mean? Sound bad. And someone should define the type in .Net 4.0 anyway.
How would model binding work? Let's assume you put this on a form with Address being null and post it as is, without changing any fields. What would be the result? Should the model binder create an Address object? Then the result would not be the same that was passed to the view. Should it keep the Address property as null? How should it detect from the posted form whether the Address entity should be created or not?
ModelBinder is a different topic, maybe they are just read-only fields for example. But yes, in the case of an address, it could make sense to create a ModelBinder that returns a null address if all the address fields are null, and otherwise returns an proper address and tries to validate it.
If there will be a way to patch all the .Net 3.5/4.0/4.5 out there I'll agree with but making a (duck-type) dependency from the C# compiler to NullPropagationExpression has some nasty consequences that I didn't though in my first proposal:
  • Projects using .Net 4.5.3 could use the feature without problems, because NullPropagationExpression will be defined.
  • Projects using any older framework will have to create their own System.Linq.Expressions.NullPropagationExpression class, here the problems start:
    • A library (like EntityFramework) will have to create his own class, but what if another library (like ASP.Net MVC) also wants to use the feature? They will create another System.Linq.Expressions.NullPropagationExpression in a different assembly. How will then the C# compiler know which class to instantiate?.
    • There could be a official Nuget package for that. Bit is this worth just for one class? And I think there could still be issues with libraries that could be used in 4.5.0/1/2/3 at the same time, because the 4.5.3 will already include the class.
The entire LINQ language feature, async and dynamic support are all implemented by a "duck-type" dependency from the C# compiler to the framework libraries and they depend on much more than just a single class. The caller member attributes are implemented with the same technique. Using these features already have the exact same problems and the exact same solutions as would upgrading the Expression API. Async does have a dedicated nuget package though much more restricted than the 4.5 implementation due to some supporting things missing from the older frameworks.
Well, it's impossible to add a new factory method to Expression class, a new value to ExpressionType enum, and libraries could have conflicts if they define their own NullPropagationExpression. It also looks like a tiny feature for taking a dependency an downloading a Nuget. But I think there's a third solution that we can explore. I will publish it in a moment in https://roslyn.codeplex.com/discussions/571077.
Still, even if .Net 4.5.3 will be the only supported Framework, by using ConditionExpression all the LINQ providers that already support ?: will support ?. from day one, maybe generating some additional CASE in SQL, or evaluating the property twice, but it will work. Then the next version could do some optimizations by recognizing the pattern.
I've build a simple project that recognizes the ConditionExpression and translates them to an internal NullPropagationExpression.

https://github.com/olmobrutall/NullPropagation/tree/master/NullPropagation

The code is not trivial and requires ExpressionComparer but is just one step more in the many that LINQ providers have to do already in order to translate to the target language (SQL for example).
Based on your code you seem to assume a.b?.c.d should be translated to a.b != null ? a.b.c.d : null. This is not the pattern and semantics used by the current compiler. What you propose makes (Func)a => a.b?.c.d and ((Expression)a => a.b?.c.d).Compile() behave differently which would be unexpected by most coders. Also for chained null-propagations the number of evaluations per property grows exponentially, e.g. in a?.b?.c?.d c is evaluated 2 times, b 4 times, a 8 times.
I don't think this is an issue for LINQ providers because the code is usually side-effect free, the current design of the operator promotes few ?. (is short circuiting) and the code will be translated to SQL (or similar) anyway, but is definitely an issue when using ?. in order to create templates for code generation.
Don't forget to implement method invoke (?.Foo(...)) and array element access (?[...]).
The implementation was not tied to MemberAccessExpression, but there where no test cases for delegate invoke, array access or indexers. I've added those and fix the ToString.
Nov 3, 2014 at 12:44 PM
I think when designing a language we also have to consider the scenarios that it will enable, not what is possible with the current libraries. Adding support for it shouldn't be hard for the MVC tem.
Write the spec on how MVC should behave in all possible places where it may encounter a null-propagation expression (in either form). Just the spec, no implementation. Then we'll see what "shouldn't be hard".
By the way I'm not even sure there would be a legacy version. MVC jumped to 4.5 without providing support for any older framework.
Like using reflection to access NullPropagationExpression you mean? Sound bad. And someone should define the type in .Net 4.0 anyway.
No, like using the NodeType property and the built-in utility classes. E.g. MVC falls back to LambdaExpression.Compile to get the value. Since LambdaExpression.Compile already handles ?. MVC uses it without actually knowing about it. The same can be done with ExpressionVisitor. There is an awful lot you can (and should) do before falling back to reflection.
ModelBinder is a different topic, maybe they are just read-only fields for example. But yes, in the case of an address, it could make sense to create a ModelBinder that returns a null address if all the address fields are null, and otherwise returns an proper address and tries to validate it.
So you say extending MVC with ?. would be useful only in an even mode limited scenario? How often would you use HtmlHelper.TextBoxFor for readonly fields? Does it really justify the costs? You can implement your own helper extensions and plug in your own model binder. Why should the MVC team implement a feature that has such limited scope and you can do it yourself if you need it?

How would the ModelBinder handle values? Should it evaluate them twice: once for determining the class should be instantiated once for setting the fields? Should it call the type converters twice? What if the request stream is non-buffered? What would be the exact condition to determine that no class should be instantiated? Value == null? Value == default(T)? What about empty string and null?
Well, it's impossible to add a new factory method to Expression class, a new value to ExpressionType enum, and libraries could have conflicts if they define their own NullPropagationExpression. It also looks like a tiny feature for taking a dependency an downloading a Nuget. But I think there's a third solution that we can explore. I will publish it in a moment in https://roslyn.codeplex.com/discussions/571077.
The compiler does not bind to "the" Expression class. The compiler binds to "an" expression class that has static factory methods with the required signatures. You can write a perfect wrapper to System.Linq.Expressions.Expression with your custom extensions that forwards existing calls to the real Expression factories and the compiler will pick yours.
Enums can have any value allowed by the underlying type.
Nov 3, 2014 at 1:42 PM
Hey man I don't know from where all this negativity comes... please take a loot at the third proposal. https://roslyn.codeplex.com/discussions/571077 I think is a nice middle ground.

BachratyGergely wrote:
I think when designing a language we also have to consider the scenarios that it will enable, not what is possible with the current libraries. Adding support for it shouldn't be hard for the MVC tem.
Write the spec on how MVC should behave in all possible places where it may encounter a null-propagation expression (in either form). Just the spec, no implementation. Then we'll see what "shouldn't be hard".
I said it's easy because I've already implemented that. We have our own set of helpers in Signum.Web and they support our Try method (already explained above). Is in this file in line 168. Is not that we use this feature every day, but sometimes is handy. Not sure if there's some MVC specific issue that I'm not aware.
By the way I'm not even sure there would be a legacy version. MVC jumped to 4.5 without providing support for any older framework.
Sure, I also assume that the new versions of the libraries that will support the feature will be updates of the latest one (MVC 6) not patches on older versions (MVC 4.3) but still worth to mention. The new solution is more future-oriented.
Like using reflection to access NullPropagationExpression you mean? Sound bad. And someone should define the type in .Net 4.0 anyway.
No, like using the NodeType property and the built-in utility classes. E.g. MVC falls back to LambdaExpression.Compile to get the value. Since LambdaExpression.Compile already handles ?. MVC uses it without actually knowing about it. The same can be done with ExpressionVisitor. There is an awful lot you can (and should) do before falling back to reflection.
Not sure if I've understood you. You stated saying "and it can do that without binding to a concrete type.", whats the difference if you bind to the new NodeType value. Anyway, I think the third solution should glad you.
ModelBinder is a different topic, maybe they are just read-only fields for example. But yes, in the case of an address, it could make sense to create a ModelBinder that returns a null address if all the address fields are null, and otherwise returns an proper address and tries to validate it.
So you say extending MVC with ?. would be useful only in an even mode limited scenario? How often would you use HtmlHelper.TextBoxFor for readonly fields? Does it really justify the costs? You can implement your own helper extensions and plug in your own model binder. Why should the MVC team implement a feature that has such limited scope and you can do it yourself if you need it?
Sure. My point is not about MVC. The ?. main use is for LINQ providers. I was just bringing MVC to focus on the possible conflicts that could arise if two libraries implement NullPropagationExpression. Anyway this issue is solved in the new solution.
How would the ModelBinder handle values? Should it evaluate them twice: once for determining the class should be instantiated once for setting the fields? Should it call the type converters twice? What if the request stream is non-buffered? What would be the exact condition to determine that no class should be instantiated? Value == null? Value == default(T)? What about empty string and null?
I'm not saying this should be the ModelBinder default behaviour, I'm saying you could implement a ModelBinder yourself that creates the Address if there is some non-empty field in the form. Anyway this is Roslyn forum, not MVC.
Well, it's impossible to add a new factory method to Expression class, a new value to ExpressionType enum, and libraries could have conflicts if they define their own NullPropagationExpression. It also looks like a tiny feature for taking a dependency an downloading a Nuget. But I think there's a third solution that we can explore. I will publish it in a moment in https://roslyn.codeplex.com/discussions/571077.
The compiler does not bind to "the" Expression class. The compiler binds to "an" expression class that has static factory methods with the required signatures. You can write a perfect wrapper to System.Linq.Expressions.Expression with your custom extensions that forwards existing calls to the real Expression factories and the compiler will pick yours.
Enums can have any value allowed by the underlying type.
I'm quite sure you can not wrap an static class an expect that you're going to receive the calls... the callers will just get name conflicts. My new solution defines ExpressionCSharp60 to give a chance to create the class in old frameworks.
Nov 17, 2014 at 5:34 AM
Any reason we couldn't just have null propagation be the default behavior. Without the need to add ?. it could just take the default value of the value your are trying to access if anything is null.

You could also make it so that ?. Would cause it to throw an error if anything was null.

Excuse the brevity , I am writing this from my phone.
Nov 17, 2014 at 5:57 AM
dcumin39 wrote:
Any reason we couldn't just have null propagation be the default behavior. Without the need to add ?. it could just take the default value of the value your are trying to access if anything is null.

You could also make it so that ?. Would cause it to throw an error if anything was null.

Excuse the brevity , I am writing this from my phone.
Yes. To much reasons to be listed here.

For starters, when I write instance.Member, as a developer, I'm asserting that instance is not null. If it is, it's an exceptional situation and an exception should be thrown.

The same reasons are behind the existence of FirstAndDefault and SingleAndDefault.

You're free to try and use only ?. instead of . and report back here if it really made things easy to you.
Nov 17, 2014 at 3:56 PM
dcumin39 wrote:
Any reason we couldn't just have null propagation be the default behavior. Without the need to add ?. it could just take the default value of the value your are trying to access if anything is null.
You mean in expression tres LINQ queries or in general?

If you mean in general, I think your design will be a really big change in the semantics of the framework, and for worst. I think nullable reference types should be avoided at compile time, and since this is a big change, at least early detected at run-time by maiking . operator assert. Otherwise will be a really forgiving language like JavaScript.

If you mean in expression trees LINQ queries, you have a point. I think the translation to SQL should be similar in most cases: just a LEFT OUTER JOIN, otherwise will be a breaking change, but you still have some benefits:
  • More clear: if you're navigating a Nullable navigatio property, use ?. and make it explicit.
  • When using ?. with value types, they get automatically nullified. No strange cast required.
  • Not all the expression trees are translated to SQL
  • An brave LINQ provider could decide to translate ?. To LEFT OUTER JOIN, while . to INNER JOIN.
You could also make it so that ?. Would cause it to throw an error if anything was null.
Well, if a feature like what you proposed will be added to JavaScript for example, I'll use !. instead.
Excuse the brevity , I am writing this from my phone.
Nov 17, 2014 at 4:07 PM
Edited Nov 17, 2014 at 4:09 PM
Olmo wrote:
dcumin39 wrote:
Any reason we couldn't just have null propagation be the default behavior. Without the need to add ?. it could just take the default value of the value your are trying to access if anything is null.
You mean in expression tres LINQ queries or in general?

If you mean in general, I think your design will be a really big change in the semantics of the framework, and for worst. I think nullable reference types should be avoided at compile time, and since this is a big change, at least early detected at run-time by maiking . operator assert. Otherwise will be a really forgiving language like JavaScript.

If you mean in expression trees LINQ queries, you have a point. I think the translation to SQL should be similar in most cases: just a LEFT OUTER JOIN, otherwise will be a breaking change, but you still have some benefits:
  • More clear: if you're navigating a Nullable navigatio property, use ?. and make it explicit.
  • When using ?. with value types, they get automatically nullified. No strange cast required.
  • Not all the expression trees are translated to SQL
  • An brave LINQ provider could decide to translate ?. To LEFT OUTER JOIN, while . to INNER JOIN.
You could also make it so that ?. Would cause it to throw an error if anything was null.
Well, if a feature like what you proposed will be added to JavaScript for example, I'll use !. instead.
Excuse the brevity , I am writing this from my phone.
JavaScript ain't that forgiving. Attempting to reference a property of a null reference still throws:
var z =x.y;  // throws if x is null or undefined
Nov 17, 2014 at 8:48 PM
True, I confuse it with how forgiving it is when the property is not defined (=set).

Anyway, JavaScript is forgiving in many other senses (automatic conversions, semicolons, undefined properties, etc...), but you're right.
Nov 18, 2014 at 6:32 AM
Olmo wrote:
True, I confuse it with how forgiving it is when the property is not defined (=set).

Anyway, JavaScript is forgiving in many other senses (automatic conversions, semicolons, undefined properties, etc...), but you're right.
I consider javascript more deceiving than forgiving about semicolons. It tricks you into think you don't need them until you do. :)
Nov 18, 2014 at 7:45 PM
dcumin39 wrote:
Any reason we couldn't just have null propagation be the default behavior. Without the need to add ?. it could just take the default value of the value your are trying to access if anything is null.
It might make more sense to do so with Nullable/Option/Maybe values. The ? would convert a value/reference to a Nullable/Option/Maybe (empty when the reference is null) and in this case the . operator would map to a Select. In which case the following LINQ query for Option<T>:
var r = from o in someObject.AsOption()
        from s in o.GetPropertyValue<string>("P")
        from i in s.ParseToInt()
        from v in i.Lookup(dict)
        select v;
could be written as:
var r = someObject?.GetPropertyValue<string>("P").ParseToInt().Lookup(dict);
where r would of type Nullable/Option/Maybe. See here and here for implementation details of the LINQ query.

But how would one distinguish between accessing a member of the Nullable/Option/Maybe struct and accessing the member of the contained value: Would a?.Value return a or a.Value (assuming a is not null)?
Nov 19, 2014 at 2:14 PM
I was talking to a coworker about this, who had some good thoughts. What if there was a base class that would make for automatic null traversal. This way it would only be the default behavior if explicitly stated. Either that or a class attribute that could be added that would make it the default behavior for that class but not necessarily any contained classes.
Nov 25, 2014 at 6:17 PM
I don't think inheritance will work here. I think null propagation could makes sense for any nullable members (or variables/parameters/return values).

By nullable I mean any Nullable<T>, T being an struct, or any value of reference type where nullable is allowed. Unfortunately in this case C# keeps this information implicit.

Then, once a member type is nullable, sometimes it makes sense to propagate nullability, and sometimes to assert for non-null value.
  • Maybe person.DateOfBirth?.ToString() ?? "-- Unknonwn -- " makes sense for reporting
  • While person.DateOfBirth.Value is the way to go if you actually want to send a Birthday letter.
Inheriting is a one shot thing, and here we need different weapons for different members in different contexts!
Nov 25, 2014 at 9:57 PM
Edited Nov 25, 2014 at 9:59 PM
dcumin39 wrote:
I was talking to a coworker about this, who had some good thoughts. What if there was a base class that would make for automatic null traversal. This way it would only be the default behavior if explicitly stated. Either that or a class attribute that could be added that would make it the default behavior for that class but not necessarily any contained classes.
I have long wished that .NET had defined an attribute that would specify that a non-virtual instance method must be invoked using "call" rather than "callvirt". If such an attribute had been defined, and C# honored it, then it would have been possible for String to define something like:
[InvokableOnNull] bool IsNullOrEmpty()
{
  return (this == null) || (this._Length == 0);
}
and for code to safely say if (someString.IsNullorEmpty()) ... rather than if (String.IsNullOrEmpty(someString) .... If types had included "get property or return default" members, then that would have greatly reduced the need for a ?. operator. That obviously didn't happen, though; thus the need for ?..

[Actually, even better might have been a means by which a type with a static method whose first parameter was a ref to the type could specify that the method should be invokable using a variation on member-referencing syntax, thus allowing code to do something like myString.:Insert(3,"George"); which would insert "George" after the third character in myString and store the result back to myString. If the same syntax were used for accessing struct fields, then confusion about when something was acting upon a storage location, versus a heap object to which a storage location held a reference, could have been largely avoided. Too late now, though.]
Nov 25, 2014 at 10:01 PM
You can already do something similar with extension method. If extension properties get made then this will be fully supported.

Personally I'd rather not have to check the semantics of null reference exceptions with . notation for different classes. I'd rather write the one extra character.
Nov 27, 2014 at 5:53 PM
mirhagk wrote:
You can already do something similar with extension method. If extension properties get made then this will be fully supported.

Personally I'd rather not have to check the semantics of null reference exceptions with . notation for different classes. I'd rather write the one extra character.
I would have liked the ?. concept better if it were an extension of the ? : operator which basically said that if the second operand start with either . or an expression enclosed in [], then evaluate the second operand if the first is non-null, or else evaluate the third (for conciseness, allow for expr1 ? .member1 ? .member2 : elseExpr to use elseExpr if either expr1 or expr1.member2 yields null). If e.g. foo.bar is supposed to yield a non-null string when foo is non-null, I think foo?.bar : "No value" would be semantically cleaner than foo?.bar ?? "No value" (if foo.bar does yield a null string when foo is non-null, the latter expression would mask the problem). That's not the concept that prevailed, however.