This project is read-only.

C# Language Design Notes for Apr 21, 2014 (Part III)

Topics: C# Language Design
Apr 30, 2014 at 6:30 PM
This is Part III. Part I is here and Part II is here.

Null propagating operator associativity

What does the following mean?
var x = a?.b.c;
People gravitate to two interpretations, which each side maintains is perfectly intuitive and the only thing that makes sense.

One interpretation is that ?. is an operator much like .. It is left associative, and so the meaning of the above is roughly the same as
var x = ((var tmp = a) == null ? null : tmp.b).c;
In other words, we access b only if a is not null, but c is accessed regardless. This is obviously likely to lead to a null reference exception; after all the use of the null propagating operator indicates that there’s a likelihood that a is null. So advocates of the “left associative” interpretation would put a diagnostic on the code above, warning that this is probably bad, and pushing people to write, instead:
var x = a?.b?.c;
With a null-check again before accessing c.

The other interpretation has been called “right associative”, but that isn’t exactly right (no pun intended): better to call it “short circuiting”. It holds that the null propagating operator should short circuit past subsequent member access (and invocation and indexing) when the receiver is null, essentially pulling those subsequent operations into the conditional:
var x = ((var tmp = a) == null ? null : tmp.b.c);
There are long discussions about this, which I will no attempt to repeat here. The “short circuiting” interpretation is slightly more efficient, and probably more useful. On the other hand it is more complicated to fit into the language, because it needs to “suck up” subsequent operations in a way those operations aren’t “used to”: since when would the evaluation of e.x not necessarily lead to x being accessed on e? So we’d need to come up with alternative versions of remote access, indexing and invocation that can represent being part of a short-circuited chain following a null propagating operator.

Conclusion

Despite the extra complexity and some disagreement on the design team, we’ve settled on the “short circuiting” interpretation.
Apr 30, 2014 at 7:26 PM
Edited Apr 30, 2014 at 9:58 PM
I'm glad that you go for the “short circuiting” version.
On the other hand it is more complicated to fit into the language, because it needs to “suck up” subsequent operations in a way those operations aren’t “used to”: since when would the evaluation of e.x not necessarily lead to x being accessed on e? So we’d need to come up with alternative versions of remote access, indexing and invocation that can represent being part of a short-circuited chain following a null propagating operator.
Why is that? With a syntax node that represents the right part of the chain as an expression that starts with a hidden parameter (tmp), the semantics should be just equals.

I tried to explain this on my comment on https://roslyn.codeplex.com/discussions/540883 the Apr 7 at 9:11 AM
Apr 30, 2014 at 9:49 PM
Olmo wrote:
I tried to explain this on my comment on http://localhost/Development.MVC/Auth/Login?referrer=%2FDevelopment.MVC the Apr 7 at 9:11 AM
For some reason, I don't think this was what you intended to paste.
Apr 30, 2014 at 10:12 PM
Of course :S fixed in place

My point is that, even if the Syntax nodes have a different name, from a Semantic point of view and on the System.Expressions API a “short circuiting” null propagating operator has to be close in structure to the nodes that represent the conditional operator:

Just as the IfTrue and IfFalse branches of a ConditionalExpression are simple expression trees, with the peculiarity that sometimes they don't get executed, the chain on the right side of a NullConditionalExpression should be a simple expression that:
  • Is conditionally executed
  • Starts on a anonymous hidden parameter (tmp in your example)
The type of the NullConditionalExpression is the type of the nullified type of rightExpression (for value types)
Apr 30, 2014 at 10:52 PM
OMG, Mads, are you serious??!?!

So now we will have a language where naively introducing variable:
return a?.b.c;
will change the meaning of the program?
var t = a?.b;
return t.c
So now we will not be able to reason about reference expression AST node behavior without it's context to handle "short circuiting"?
What is the type of "a?.b" expression in "a?.b.c"?

I just can't believe it
Apr 30, 2014 at 11:15 PM
ControlFlow wrote:
So now we will not be able to reason about reference expression AST node behavior without it's context to handle "short circuiting"?
What is the type of "a?.b" expression in "a?.b.c"?
If it's right associative, there's no a?.b in a?.b.c. But there's b.c.
var t = b.c;;
return a?.t;
Apr 30, 2014 at 11:30 PM
ControlFlow wrote:
So now we will not be able to reason about reference expression AST node behavior without it's context to handle "short circuiting"?
What is the type of "a?.b" expression in "a?.b.c"?
The type of a?.b is the (nullable) type of b.

The counter-intuitive idea is that a?.b is not a sub-expression of a?.b.c just as a == null ? null: a.b is not a a sub-expression of a == null ? null: a.b.c.
a?.b
a.Try(@.b)
a.Try(tmp => tmp.b)
(var tmp = a) == null ? null: temp.b


a?.b.c
a.Try(@.b.c)
a.Try(tmp => tmp.b.c)
(var tmp = a) == null ? null: temp.b.c
Apr 30, 2014 at 11:32 PM
PauloMorgado wrote:
ControlFlow wrote:
So now we will not be able to reason about reference expression AST node behavior without it's context to handle "short circuiting"?
What is the type of "a?.b" expression in "a?.b.c"?
If it's right associative, there's no a?.b in a?.b.c. But there's b.c.
var t = b.c;;
return a?.t;
You're saying that myFriend?.Name.Length is translated to
var t = Name.Length
return myFriend?.t; 
This doesn't make any sense.
May 1, 2014 at 12:13 AM
Edited May 1, 2014 at 12:13 AM
Just a crazy idea: why not to have 2 operators ?. and .? one is right-associative and another one is left?
May 1, 2014 at 8:38 AM
Edited May 1, 2014 at 8:39 AM
hazzik wrote:
Just a crazy idea: why not to have 2 operators ?. and .? one is right-associative and another one is left?
Because the "short circuiting" version is just better in every way: is faster, and avoids polluting the rest of the chain with ?. everywhere.

The only drawback is that is a little bit harder to implement and understand, but you don't solve it having two, instead you make this problem worst.
May 1, 2014 at 11:57 PM
How often would refTypeExpr ? refTypeExpr.someMember : null be useful as compared with refTypeExpr ? refTypeExpr.someMember : someOtherExpr? I find myself thinking that what's really needed is not so much to have something that defaults to null, but rather something that would allow code which--but for the duplication--would be equivalent to
refTypeExpr ? 
   refTypeExpr.refTypeMember ?
     refTypeExpr.refTypeMember.memberValue :
     defaultValue :
defaultValue
to be written more concisely. The defaultValue would probably more often than not be null, and it might be worth special-casing syntax for that, but I would not expect the null default to be overwhelmingly dominant.

Having the ? operator accept a reference as its left-hand operator in cases where the middle operator starts with . or [ and allowing inner : terms to be omitted in cases which would not lead to ambiguity, would seem to offer vastly more usage cases than restricting the operation to reference types. If the final member of interest returns an int, one could perhaps say:
int result = (myRef?.member1?.member2?.someIntProperty).ValueOrDefault(desiredDefault);
but I would not regard that as being as clean as something like:
int result = myRef?.member1?.member2?.someIntProperty : desiredDefault;
Parentheses would be required in cases where there would be more than one : or ?? to which a given ?. could bind, but would not be necessary in typical usage cases.

Note that
int result = myRef?.member1?.member2?.someStringProperty : desiredDefault;
and
int result = myRef?.member1?.member2?.someStringProperty ?? desiredDefault;
would have different behavior if myRef.member1.member.someStringProperty could be evaluated and was null. The former code would return that null, while the latter would return desiredDefault.
May 2, 2014 at 1:14 PM
Edited May 2, 2014 at 1:27 PM
Am I right in understanding that following code will throw ArgumentNullExpression even in the case of short-circuiting implementation?
class A {
    public B b { get; set; }
}

class B {
    public int c { get; set; }
}

var a = new A();
int? x = a?.b.c; //throws
After all, this would translate to (a == null ? null : a.b.c). That is fine for me, but you still have to write a?.b?.c for the whole expression to be safe.

I think that most people advocating left associativity do not understand that in their case, they must write b?.c part in expression a?.b?.c not because b might be null, but because earlier part (a?.b) might result in null.

I also think that behavior of short-circuiting operator is very easy to explain: If you have question mark after member access, whole expression will be null when the member will be null. That's pretty simple to me.
May 2, 2014 at 2:59 PM
No, it would not throw ArgumentNullExpression; however, it would throw NullReferenceException, yes.
May 2, 2014 at 5:02 PM
After all, this would translate to (a == null ? null : a.b.c). That is fine for me, but you still have to write a?.b?.c for the whole expression to be safe.
If a might legitimately be null, but a.b should never legitimately be null in cases where a is non-null, an exception should be thrown if a.b is evaluated and found to be null. One of the big reasons I want to allow the "fallback" value to be explicitly specified is that testing the result of the overall expression for null will not reveal whether the last thing was evaluated as null, or whether evaluation didn't make it that far. If the last thing should never legitimately return null, code which replaces a null returned by it with a default value will hide an error.

The purpose of ?. shouldn't be to increase the conveninece of writing code that doesn't throw exceptions--it should be to increase the convenience of writing code which throws exceptions only when it should.
May 2, 2014 at 6:24 PM
Edited May 2, 2014 at 6:28 PM
Hi,

Can this operator be used to avoid unwanted side effects? Or must it always be used in an assignment expression?

For example, would this makeshift program throw ArgumentNullException or not?
static class UriExtensions
{
    public static void SetCurrentDirectory(this Uri directory)
    {
        if (directory == null) throw new ArgumentNullException();
        Environment.CurrentDirectory = directory;
    }
}

class Program
{
    static void Main()
    {
        Uri directory = null;
        directory?.SetCurrentDirectory();
    }
}
If the answer is that the program does not throw ArgumentNullException, then it seems to me that short-circuiting behavior is required for consistency.

For example, it would seem strange to me if the former program does not throw, yet the following program throws NullReferenceException:
static void Main()
{
    Foo a = null;
    var c = a?.b.GetHashCode();
}
- Dave
May 2, 2014 at 6:30 PM
FYI, I corrected my latter example :)
May 2, 2014 at 6:48 PM
Edited May 2, 2014 at 6:48 PM
davedev wrote:
var c = a?.b.GetHashCode();
If I were in charge of writing the language, I would forbid that construct because GetHashCode() does not return something of reference type, and would I require either:
var c = a?.b.GetHashCode() : 0;

var c = a?.b.GetHashCode() ?? 0;
if the goal was to return an integer that defaulted to zero, or
var c = a?.b.GetHashCode() : (int?)null;

var c = a?.b.GetHashCode() ?? (int?)null;
if the goal was to return a null-valued int? if the result was null, or a non-null int? if it wasn't.

When the preceding term is a non-nullable value type, the : and ?? would behave identically. The distinction between them would be the behavior when the preceding term is a nullable or reference type. The : operator would return the left-hand operator in all cases where it was evaluated, while ?? would only return it if it was evaluated and was not null. Note that the special binding of ?. and ?? should not require that the term between them be a nullable type. Given
class Wow<T> { public T Value; }
T test<T>(Wow<T> it, T defaultValue)
{
   return it?.Value ?? defaultValue;
}
there's no clean way by which the compiler could ensure that the "left operand" of ?? was nullable (it can't use Nullable<T> without a struct constraint) but it shouldn't need to. If it is null, return defaultValue. Otherwie if T isn't nullable, return it.Value. Otherwise get it.Value, check if it's null, and return it.Value or defaultValue as appropriate.
May 2, 2014 at 7:12 PM
Hi supercat,

Well, yours is an interesting point, though just to be clear the type of the return value of b.GetHashCode() is irrelevant to the point of my post -- it could just as well have been b.ToString() and my question stands.

As for your first point, I would prefer if c were simply typed as int?. I.e., whenever a struct appears as the output of a potentially short-circuited sub-expression, it is automatically lifted into a nullable.

As for your second point, I think your use of a generic type implies the need for the Maybe<T> type to be included in the FCL. Alternatively, the compiler should simply disallow that usage of the operator. I see no reason why what would be an intuitive and reasonable solution to the former scenario should be affected at all by the problems of the latter scenario.

- Dave
May 2, 2014 at 8:23 PM
davedev wrote:
As for your first point, I would prefer if c were simply typed as int?. I.e., whenever a struct appears as the output of a potentially short-circuited sub-expression, it is automatically lifted into a nullable.
The runtime has no means via which a T can be lifted into a Nullable<T> without a struct constraint on T.

Further, I'm curious how often the real goal, in cases where an intermediate term is null, would be to have a null-valued result, and how often the goal would be to perform some other default behavior? If e.g. the operator were restricted to class types and didn't allow a default value to be specified, I would expect it would often get used in expressions like:
return a?.b?.c.d ?? e;
Such an expression would throw an exception if return e if a.b is non-null but a.b.c is null; if a.b.c is non-null and a.b.c.d is null, however, it would return e rather than returning null. Clearly, there is an expectation that if a.b is non-null, a.b.c.d will be evaluable and if it isn't an exception should be thrown. I'm curious, however, how often the fact that the expression silently returns e when a.b.c.d is null would be desired versus simply tolerated.

Having ?. bind with : or ?? would avoid any requirement that it have a default value; if the : or ?? were optional when used with class types, the only downside I can see would be an occasional need for extra parentheses. Do you see any other downside to allowing the default value to be specified?
May 2, 2014 at 8:43 PM
supercat wrote:
Do you see any other downside to allowing the default value to be specified?
If I understood you corrently, you want that this code:
a?.b.c ?? e
to be translated to
(var tmp = a) == null? tmp.b.c : e
instead of
((var tmp = a) == null? tmp.b.c : null) ?? e;
I think is unexpected for a programmer to get a null value when c is null.

I also don't think that a default value that is not null is a common enough scenario to complicate the feature more with the : operand. You can always fallback to classic conditional operator.
May 2, 2014 at 9:13 PM
Edited May 2, 2014 at 9:27 PM
Olmo wrote:
If I understood you corrently, you want that this code...

```c#
a?.b.c ?? e
I would have a?.b : c return c only if a is null, and return a.b otherwise (even if that happens to be null). I would have a?.b ?? c return c if either a or a.b is null. If a.b is not a nullable or reference type, the latter expression shouldn't try to make it nullable but should simply have it behave like the former. If it's a generic, it should behave like the latter when the type is a nullable or reference type and the former otherwise.

As for complication, the consequences of hoisting value types to nullable, are worse. Further, I can think of no way to have ?. have a sensible default behavior with unconstrained generic types.
May 3, 2014 at 10:46 AM
supercat wrote:
As for complication, the consequences of hoisting value types to nullable, are worse. 7
I think lifting the type to nullable is the only sensible thing, some examples:

What is the Id of a null person? -> null
What is the DateOFBirth of a null person? -> null
What is the age of a null person? -> null
Further, I can think of no way to have ?. have a sensible default behavior with unconstrained generic types.
Actually, your operator has a sensible behavior only when the unconstrained generic types is the return type of the expression, not when it is the expression you check for null:
class Box<T>
{
    T value; 
    
    string ToString(){
        return "Box " + value?.ToString() ? "empty"; //Also doesn't compile
    }
}
At the end of the day, the Null Propagating Operator is a specialization of a conditional for the common case of checking for null and returning null on member chain expressions. If you need something more general, use the conditional operator.
May 3, 2014 at 4:23 PM
Olmo wrote:
Actually, your operator has a sensible behavior only when the unconstrained generic types is the return type of the expression, not when it is the expression you check for null:
    return "Box " + value?.ToString() ? "empty"; //Also doesn't compile
My proposal would be for the proper syntax to be either return "Box " + value?.ToString() : "empty"; or return "Box " + value?.ToString() ?? "empty"; I would not expect the single-question mark before "empty" to compile.

I don't see the problem with behavior; if the operators have the meaning I'm proposing, given:
interface IFactory<T> { T Create(); } 

void MakeOrDefault1<TFac,TRes>(TFac factory, TRes defaultResult) where TFac: IFactory<TRes>
{
   return tactory?.Create() : defaultRes;
}
void MakeOrDefault2<TFac,TRes>(TFac factory, TRes defaultResult) where TFac: IFactory<TRes>
{
   return tactory?.Create() ?? defaultRes;
}
The first method should return factory == null ? defaultResult : factory.Create(). The second, factory == null ? defaultResult : (factory.Create() ?? defaultResult). Note that there is no problem 'sensibly' testing whether an unconstrained generic is null. There are some types for which the comparison will never yield true, but the situation's not much different from if ((x*2)==y) in cases where y might be an odd number.

Olmo wrote:
What is the age of a null person? -> null
I think "name" would be a more helpful example, since string is inherently a nullable type, and names are not expected to be unique identifiers. I would suggest that the proper way to properly format the spouse's name would be:
FormatName(person.Spouse?.Name : NonexistentPersonDefaultName);
If Fred Jones has a wife, but for whatever reason her name was null, it should be handled as a person who exists but has a null name. Writing the code as
FormatName(person.Spouse?.Name ?? NonexistentPersonDefaultName);
would erroneously say Fred had no wife in such a situation.
May 3, 2014 at 4:59 PM
Edited May 3, 2014 at 5:03 PM
supercat wrote:
Olmo wrote:
Actually, your operator has a sensible behavior only when the unconstrained generic types is the return type of the expression, not when it is the expression you check for null:
    return "Box " + value?.ToString() ? "empty"; //Also doesn't compile
My proposal would be for the proper syntax to be either return "Box " + value?.ToString() : "empty"; or return "Box " + value?.ToString() ?? "empty"; I would not expect the single-question mark before "empty" to compile.
You right, was a typo I wanted to write : or ??. My point is that value? doesn't make a lot of sense for unconstrained generic types (when T is an struct)
I don't see the problem with behavior; if the operators have the meaning I'm proposing, given:
interface IFactory<T> { T Create(); } 

void MakeOrDefault1<TFac,TRes>(TFac factory, TRes defaultResult) where TFac: IFactory<TRes>
{
   return tactory?.Create() : defaultRes;
}
void MakeOrDefault2<TFac,TRes>(TFac factory, TRes defaultResult) where TFac: IFactory<TRes>
{
   return tactory?.Create() ?? defaultRes;
}
The first method should return factory == null ? defaultResult : factory.Create(). The second, factory == null ? defaultResult : (factory.Create() ?? defaultResult). Note that there is no problem 'sensibly' testing whether an unconstrained generic is null. There are some types for which the comparison will never yield true, but the situation's not much different from if ((x*2)==y) in cases where y might be an odd number.
Well, it looks to me that comparing an unconstrained generic type to null is misleading and I will consider make it a warning. But right now it compiles.
Olmo wrote:
What is the age of a null person? -> null
I think "name" would be a more helpful example, since string is inherently a nullable type, and names are not expected to be unique identifiers. I would suggest that the proper way to properly format the spouse's name would be:
FormatName(person.Spouse?.Name : NonexistentPersonDefaultName);
If Fred Jones has a wife, but for whatever reason her name was null, it should be handled as a person who exists but has a null name. Writing the code as
FormatName(person.Spouse?.Name ?? NonexistentPersonDefaultName);
would erroneously say Fred had no wife in such a situation.
My point is that NonexistentPersonDefaultName is, most of the time, just null. Also null is the only value that also compose nicely in a chain.

Is the : or ?? in your proposal optional or mandatory?

With your proposal, could you write more than one ?. like in:
customer?.Address?.City?.State : "-- unknown state --"
Or you need one : for each ?. ?

With the standard proposal is just
customer?.Address?.City?.State ?? "-- unknown state --"
May 3, 2014 at 6:37 PM
Edited May 3, 2014 at 6:46 PM
Comparing an unconstrained generic to null may appear ugly, and I'm really not happy about the syntax (I think there should be a separate isnull intrinsic or operator), but there are times when it is semantically necessary to specially handle the case where an unconstrained generic value is null. The situation would be somewhat like trying to check whether a List<T> and List<U> have any items in common. If the lists happen to be List<Cat> and List<Dog> and code recognized that the item types were totally unrelated classes, it could safe itself the effort of examining either list's contents, but checking whether the list types could overlap should be seen as a potential performance improvement, rather than a semantic necessity, since the only effect of skipping the step would be to have the computer waste time checking whether Felix, Garfield, and Sylvester were equivalent Rover, Lassie, and Benji (and finding out that they weren't).

With regard to NonexistentPersonDefaultName, perhaps my identifier choice was poor, Maybe for purposes of the example I should have just used a string literal NONE whereas FormatName would respond to a null name with <NAME UNKNOWN>. If someone wants to know "Is Fred married", there's a huge difference between "Spouse: NONE" and "Spouse: <NAME UNKNOWN>".

I would propose that the : or ?? be optional in the case where the last term in the chain of .-and-?.-connected items has a reference or nullable type, and required when it does not; I would require parentheses in cases where there could otherwise be a real ambiguity but don't think such situations would arise overly often. The expression foo?.bar ?? boz; should behave semantically like (foo?.bar) ?? boz in the cases where foo.bar would be nullable, and like foo?.bar:boz in cases where it would not. The latter-case behavior would be semantically equivalent to hoisting the type of foo?.bar to a nullable type and then converting it back to the non-nullable value type, but would not require the compiler to go through the machinations of hoisting an unconstrained generic.
With the standard proposal is just
 customer?.Address?.City?.State ?? "-- unknown state --"
Unless customer.Address.City.State == null would be a valid condition and "-- unknown state --" would be the correct response, I would consider the above code to be semantically incorrect. If customer.Address.City.State == null is not a valid condition, the bug might well have no practical impact, but fundamentally it is only correct to make the substitution in cases where null represent a valid case that should be remapped.
May 3, 2014 at 11:00 PM
supercat wrote:
Comparing an unconstrained generic to null may appear ugly, ... but there are times when it is semantically necessary to specially handle the case where an unconstrained generic value is null.
Great point, supercat. I just noticed that
static void f<T>(T x) 
{
    var a = x ?? default(T); // error
    var b = (x != null) ? x :  default(T); // works fine
}
This is what the spec says, and what the compiler does, but it disagrees with my intuition that ?? is like a null-check.
May 4, 2014 at 10:12 AM
supercat wrote:
Comparing an unconstrained generic to null may appear ugly, and I'm really not happy about the syntax (I think there should be a separate isnull intrinsic or operator), but there are times when it is semantically necessary to specially handle the case where an unconstrained generic value is null.
I don't see why the problem is syntactic. I think the underlying problem is that nullability should be orthogonal to reference/value type at the CLR level. But this is a different issue.
The situation would be somewhat like trying to check whether a List<T> and List<U> have any items in common. If the lists happen to be List<Cat> and List<Dog> and code recognized that the item types were totally unrelated classes, it could safe itself the effort of examining either list's contents, but checking whether the list types could overlap should be seen as a potential performance improvement, rather than a semantic necessity, since the only effect of skipping the step would be to have the computer waste time checking whether Felix, Garfield, and Sylvester were equivalent Rover, Lassie, and Benji (and finding out that they weren't).
Sorry but I can not follow your comparison. What unconstrained generic types have to do with this optimizations for comparing List for equality?
With regard to NonexistentPersonDefaultName, perhaps my identifier choice was poor, Maybe for purposes of the example I should have just used a string literal NONE whereas FormatName would respond to a null name with <NAME UNKNOWN>. If someone wants to know "Is Fred married", there's a huge difference between "Spouse: NONE" and "Spouse: <NAME UNKNOWN>".
Of course there is, except if you use null for both. If I would have to print a Word report I will write something like:
spose == null ? "-- None --" :
spose.Name == null ? "-- Name unknown --"
spose.Name;
But on a Excel report maybe just this makes more sense
spose?.Name;
Your proposal looks like suits better for the first scenario, but I'm not really sure how it will look like. Maybe something like this?:
spose?.Name?.ToString() : "-- Name unknown --":  "-- None --"
I would propose that the : or ?? be optional in the case where the last term in the chain of .-and-?.-connected items has a reference or nullable type, and required when it does not; I would require parentheses in cases where there could otherwise be a real ambiguity but don't think such situations would arise overly often. The expression foo?.bar ?? boz; should behave semantically like (foo?.bar) ?? boz in the cases where foo.bar would be nullable, and like foo?.bar:boz in cases where it would not. The latter-case behavior would be semantically equivalent to hoisting the type of foo?.bar to a nullable type and then converting it back to the non-nullable value type, but would not require the compiler to go through the machinations of hoisting an unconstrained generic.
Why lifting non-nullable value types to Nullable<T> concerns you? I see it as just the only sensible thing and I don't think there is a big performance penalty. Many copies of the value type are going to be made anyway (Property -> Expression -> result variable or parameter)
With the standard proposal is just
 customer?.Address?.City?.State ?? "-- unknown state --"
Unless customer.Address.City.State == null would be a valid condition and "-- unknown state --" would be the correct response, I would consider the above code to be semantically incorrect. If customer.Address.City.State == null is not a valid condition, the bug might well have no practical impact, but fundamentally it is only correct to make the substitution in cases where null represent a valid case that should be remapped.
Since we have settle down to "short circuiting", this expression expect that customer, Address, City and State could all have null as a valid value. The nice thing of the Null propagating operator is that it composes nicely because all the operators agree on null as the missing value. Of course there are cases where you could want to differentiate the different cases, but then I don't think you could get much better than a classing conditional operator:
customer == null ? "-- No customer--" :
customer.Address == null ? "-- No address--" :
customer.Address.City == null ? "-- No city--" :
customer.Address.State == null ? "-- No state--" :
customer.Address.State;
May 4, 2014 at 1:31 PM
The other interpretation has been called “right associative”, but that isn't exactly right (no pun intended): better to call it “short circuiting”.
Why is it not exactly right-associative?

I'm also unclear what the syntax tree would look like for the right associative interpretation. Clearly, the null-propagating operator must be the root. In a?.b.c, how would the b.c part be stored? b cannot be a member access because we don't have an instance to call the member b on. Duplicating a in the tree does not seem like a good idea and semantically incorrect regarding side-effects.
May 4, 2014 at 5:57 PM
Olmo wrote:
Sorry but I can not follow your comparison. What unconstrained generic types have to do with this optimizations for comparing List for equality?
Does it make no sense to check whether a List<Dog> and a List<Cat> have items in common? I would suggest that comparing lists of types which are known to be disjoint would be silly, but comparing lists of types which may or may not be disjoint is perfectly reasonable. Likewise, comparing something which is known to be a non-nullable value type woudl be silly, but comparing an unconstrained generic to a null is reasonable.
With regard to NonexistentPersonDefaultName, perhaps my identifier choice was poor, Maybe for purposes of the example I should have just used a string literal NONE whereas FormatName would respond to a null name with <NAME UNKNOWN>. If someone wants to know "Is Fred married", there's a huge difference between "Spouse: NONE" and "Spouse: <NAME UNKNOWN>".

I would propose that the : or ?? be optional in the case where the last term in the chain of .-and-?.-connected items has a reference or nullable type, and required when it does not; I would require parentheses in cases where there could otherwise be a real ambiguity but don't think such situations would arise overly often. The expression foo?.bar ?? boz; should behave semantically like (foo?.bar) ?? boz in the cases where foo.bar would be nullable, and like foo?.bar:boz in cases where it would not. The latter-case behavior would be semantically equivalent to hoisting the type of foo?.bar to a nullable type and then converting it back to the non-nullable value type, but would not require the compiler to go through the machinations of hoisting an unconstrained generic.
Why lifting non-nullable value types to Nullable<T> concerns you? I see it as just the only sensible thing and I don't think there is a big performance penalty. Many copies of the value type are going to be made anyway (Property -> Expression -> result variable or parameter)
If the return type of Foo.Bar is a T, what should be the type of
var blah = Foo?.Bar;`
There is no mechanism within the CLR via which it could be a Nullable<T> without T having a struct constraint. Regardless of whether it would be desirable to have it be a T when T is a reference or nullable type and Nullable<T> otherwise, there is no mechanism in the CLR for that. Note that unlike C++ templates, .NET generics require that the same CIL code be generated for all types, and thus the only differences in behavior between structure, nullable, and references types that can be accommodated are those provided for within the CLR.
Unless customer.Address.City.State == null would be a valid condition and "-- unknown state --" would be the correct response, I would consider the above code to be semantically incorrect. If customer.Address.City.State == null is not a valid condition, the bug might well have no practical impact, but fundamentally it is only correct to make the substitution in cases where null represent a valid case that should be remapped.
Since we have settle down to "short circuiting", this expression expect that customer, Address, City and State could all have null as a valid value. The nice thing of the Null propagating operator is that it composes nicely because all the operators agree on null as the missing value. Of course there are cases where you could want to differentiate the different cases, but then I don't think you could get much better than a classing conditional operator:
That requirement would only apply if one were required to use the same operators in cases where null was a valid value and in cases where it wasn't.
customer == null ? "-- No customer--" :
customer.Address == null ? "-- No address--" :
customer.Address.City == null ? "-- No city--" :
customer.Address.State == null ? "-- No state--" :
customer.Address.State;
That ends up with a lot of redundant property accesses. Perhaps inline var declarations would be better, but my proposal would write the expression as
customer?(.Address?(.City ?? "--No city--") : "--No address--") : "--No customer--")
Perhaps an operator which pulled out the null case first would be cleaner. Perhaps
customer !? "--No customer" : .Address !? "--No address--" : .City ?? "No city" 
Since the real need here is to be able to use an expression twice (once to test for null, and once as the left-hand side of a ".") perhaps the real focus should be in allowing efficient means to accomplish that. I'm not super keen on the usage of non-alphanumeric characters for such purposes [I prefer vb-style words] but I don't know how one could use words in C# without creating ambiguity with possible identifiers. Otherwise I'd suggest something like:
with (customer; . ==null ? "--No customer--" : with(.Address; .==null ? "--No address--" : .City ? "--No city--");
The with block would have two portions separated by ;; the first would evaluate an expression, and within the second part .. would be synonymous with either the expression, or with the expression followed by a ., depending upon syntactic requirements.

In any case, the most important thing is to have a concise way of evaluating an expression once, deferencing it if non-null, and doing something else if null. Being able to declare variables within an expression would reduce the importance of being able to use ?. for such a purpose.
May 4, 2014 at 6:04 PM
xor88 wrote:
I'm also unclear what the syntax tree would look like for the right associative interpretation. Clearly, the null-propagating operator must be the root. In a?.b.c, how would the b.c part be stored? b cannot be a member access because we don't have an instance to call the member b on. Duplicating a in the tree does not seem like a good idea and semantically incorrect regarding side-effects.
I think a?.b.c as proposed would be semantically equivalent [excluding things like name collisions] to (var temp=(a); temp==null ? null : temp.b.c). In terms of syntax tree, the left-hand operand of .b.c would be a temporary variable.
May 4, 2014 at 6:10 PM
supercat wrote:
I think a?.b.c as proposed would be semantically equivalent [excluding things like name collisions] to (var temp=(a); temp==null ? null : temp.b.c). In terms of syntax tree, the left-hand operand of .b.c would be a temporary variable.
I don't think it would be a temporary because that would not capture the fact that a null-prop operator was used. You couldn't analyze this expression programmatically. It would be a lowering. I can lower a?.b.c to what you wrote but I now no longer have the information that this expression stemmed from a null-prop operation. It must be a full-fledged syntax tree node.
May 4, 2014 at 7:25 PM
xor88:

If you ser the first comments and the link, when I speak about NullConditionalExpression, is already an expression that contains three nodes:
  • The right expression, that could produce a null.
  • The parameter expression, just to identify it.
  • The left expression, that should start on parameter expression and contains only MethodCallExpression, MemberExpresssion and InvocationExpression
Because thereis a special node for if (NullConditionalExpession) is easier to recognize, and because it relies on a parameter expression, we can keep the left expression as an standard expression, without relying in a 'member list' of some sort that will create a lot of redundancy
May 4, 2014 at 7:45 PM
I am still concerned that a?.b looks and feels way too much like a.b, therefore the developers are going to expect that the refactorings like in ControlFlow's example are valid.

I think the way to combine the usefulness of right-associative semantics and expressiveness of . is... to choose another notation for the operator, in the best case not implying the left-associativity. Right now \ and ~ come to my mind.

Another syntactic idea would be keeping the left associativity with the possibility of specifying brackets: instead of a?.b we write a.[b], so the right-associative a?.b.c will be denoted as a.[b.c]. Or maybe curly braces instead. This form can never be read as (a.b).c.
May 17, 2014 at 7:14 PM
It must be short circuiting.

If it is then a?.b.c and a?.b?.c both have meaning. If it's not short circuiting, a?.b.c makes no sense.
May 18, 2014 at 7:16 PM
I'm more in favor of the left-associative view. Certainly, the short-circuiting view is more flexible than the left-associative view, that's for sure.

The trouble is that the short-circuiting view is flexible in the wrong way. Generally, once you start a monadic expression, most likely you intend to follow through with it to the end. Something like:
var x = a?.b?.c ?? 0;
When a monadic chain is aborted half way through, as in the opening question, it's very confusing. Either you should follow through and carry the monad to the end, or you shouldn't start at all. The short-circuiting approach seems like a way of "forgiving" the author for not following through by letting the half-monadic expression "do something interesting" anyway.

It would be nice if there were some sort of implicit pressure in the language to get the author to naturally gravitate toward a fully monadic or a fully non-monadic expression, which is precisely what is enabled by thinking of it as left-associative. Also, it has the nice property of being consistent with pretty much all other binary operators, and not being a special case.

Basically, there should be no mixing and matching of ?. and . in a single expression. Either one or the other, otherwise you probably made a mistake.

Unless, can someone propose a good counterexample?
May 18, 2014 at 11:01 PM
gzak wrote:
Basically, there should be no mixing and matching of ?. and . in a single expression. Either one or the other, otherwise you probably made a mistake.
I would prefer not to have a language in which it is much easier to say:
If foo is null, evaluate to null
If foo is non-null but foo.bar is null (even though it shouldn't be) return null
Otherwise return foo.bar.boz;
than to say
If foo is null, evaluate to null
If foo is non-null but foo.bar is null (it shouldn't be), throw an exception
Otherwise return foo.bar.boz;
If foo is either supposed to be null or else identify a valid instance (i.e. one where foo.bar is non-null), then code should throw an exception if that expectation does not hold. Have the overall expression yield null in such a case, suggesting the existence of an expected condition, would cover up potential errors.

My personal preference would be to have ?. be two separate tokens, and say that if the second operand of ? : starts with ., the left operand will be checked for whether it is null, and if not null will feed that ..; otherwise if it is null, the third argument would be returned instead, but with the provision that multiple ? . sequences may be used with a single : in cases that fit certain patterns.
May 19, 2014 at 7:46 AM
Edited May 19, 2014 at 8:12 AM
What about the following "null-safe" null-coalescing operator ?? null:
var x = a.b.c ?? null;
? If any of a, b (and c as well) is null, x is evaluated to null. It is simply translated into something like:
var x = {
    typeof(c) tmp;
    try {
        tmp = a.b.c;
    } catch (NullReferenceException) {
        tmp = null;
    }
    return tmp;
}
If catching NullReferenceException is too expensive, it can be replaced with a series of if ()s, of course.

If you need to provide a default value, append the null-coalescing operator again:
var x = a.b.c ?? null ?? 100;
It reads "assign a.b.c to x, but if any of a, b, c is null, assign 100 instead."

Pros over the current proposal:
  • Much simpler and easier-to-read syntax
  • Existing code can be easily modified by just adding ?? null
May 19, 2014 at 4:22 PM
junyoung wrote:
What about the following "null-safe" null-coalescing operator ?? null:
var x = a.b.c ?? null;
? If any of a, b (and c as well) is null, x is evaluated to null. It is simply translated into something like:
That would break the behavior of currently legal code.

As an aside, since the team already met and decided on implementing ?. as RA/"short-circuiting" is there any real point to continue rehashing that argument?
May 19, 2014 at 5:26 PM
Halo_Four wrote:
That would break the behavior of currently legal code.
Right, but the current legitimate use of ?? null is completely redundant:
var x = a ?? null;
and isn't used anywhere AFAIK.
As an aside, since the team already met and decided on implementing ?. as RA/"short-circuiting" is there any real point to continue rehashing that argument?
?. operator in the currently proposed syntax/semantics, including short-circuiting, IMHO, is more troublesome than it gives.
May 20, 2014 at 4:41 AM
Edited May 20, 2014 at 4:47 AM
I would greatly prefer if the operator included a second, optional parameter.

Like Olmo and Timwi (discussed at https://roslyn.codeplex.com/discussions/540883), I also have a set of static NullOr extention methods. The difference is that my methods have an optional tail parameter that defaults to null but can be specified if needed. Here is the psuedo code:
public static TResult NullOr<TInput,TResult> (TInput input, Func<TInput,TResult> ifNotNullTransform, TResult resultIfNull = null)
{
   return input == null ? resultIfNull : ifNotNullTransform(input);
}
This allows me to write expressions like this:
var name = customer.NullOr( c=> c.Name, "Unknown User") ?? "Missing Name";
That is a pretty dumb example, but it allows for easily dealing with some complex cases, and the compiler typically inlines these calls as well -- at least when running with inlining enabled.

First, I would recommended extending the existing "??" operator to make it more powerful to allow specifying an optional ":." separated chain clause.

With that in place, my code above could be written as:
var name = customer ?? "Unknown User" :.Name ?? "Missing Name";
Which is the same as:
string name;
if (customer == null)
{
  name = "Unknown User";
} else {
  string tmp = customer.Name;
  name = tmp == null ? "Missing Name" : tmp;
}
Secondly, I would recommend that the operator "?." have an optional ":" extension that allows overriding the default null value. Here is an example of what that would look like:
var name = customer ?.Name : "Missing Name" ?? "Unknown User";
Which would be the same as the following (taken literally):
string name = null;
if (customer != null)
{
  string tmp = customer.Name;
  name = tmp == null ? "Missing Name" : tmp;
}

if (name == null)
{
  name = "Unknown User";
}
The compiler should be able to optimize most cases (if not all -- would need to think about it more) to this:
string name = null;
if (customer != null)
{
  string tmp = customer.Name;
  name = tmp == null ? "Missing Name" : tmp;
} else {
  name = "Unknown User";
}
Without adding the optional ":" extension to "?." we could only do something like this:
var name = customer ?.Name ?? "Unknown User or Missing Name";
I mention that case explicitly because it evaluates to the constant "Unknown User or Missing Name" both when either customer or customer.Name are null.

Thirdly (knowing this may just be a matter of taste...), I suggest suggest "??." rather than "?.". My reasoning is that since the single question mark is already used for the ternary operator and the nullable value operator, it involves extra brain cycles to answer, "what does this single quote mean?" The double question mark operator ("??") is already used for dealing with null so some variant of "??" seems to have more conceptual affinity for dealing with nulls. Lastly, it isn't any more difficult to quickly type "??." than "?.".

To me, it seem this is easier to decipher:
var name = customer ??.Name : "Missing Name" ?? "Unknown User";
var name = customer ??.Name ?? "Unknown User or Missing Name";
than it is to decipher this:
var name = customer ?.Name : "Missing Name" ?? "Unknown User";
var name = customer ?.Name ?? "Unknown User or Missing Name";
I supposed I could get used to either, but I think the "??." pops more than "?." -- again, may just be personal taste. I would really like "?!." (since the "!" generally means "not" or "opposite" and we're essentially doing to opposite of "??"); however, the "!" is far enough away to make that a harder sell...

Any thoughts?
May 20, 2014 at 5:48 AM
MarkSmeltzer wrote:
string name;
if (customer == null)
{
  name = "Unknown User";
} else {
  string tmp = customer.Name;
  name = tmp == null ? "Missing Name" : tmp;
}
I prefer:
var name = customer != null ? (customer.Name ?? "Missing Name") : "Unknown User";
to yours:
var name = customer ?.Name : "Missing Name" ?? "Unknown User";
?. : ?? is not so useful in this case. ;-)
May 20, 2014 at 5:52 AM
That syntax is just a reduction of the NullOr extension method, which can handle much more complex and interesting cases that the one in my simplistic example.

What it comes down to is that I often need to override null with another value, which is what the extension demonstrates.

May 21, 2014 at 6:19 AM
Edited May 21, 2014 at 6:22 AM
Let's take a step back for a second. Fundamentally, what's the difference between this:
var x = a?.b.c;
And this:
var x = a?.b?.c;
Assuming the short-circuiting behavior of the ?. operator and that c is of type int. What is the inferred type and value of x under various conditions? Isn't it the same in both cases? Of so, why allow two slightly different syntaxes for the same thing, especially when the former is only useful as a means of forgiving the author for not writing the latter? Why not just encourage the user to write it correctly in the first place?
May 21, 2014 at 7:06 AM
Edited May 21, 2014 at 7:12 AM
gzak wrote:
Fundamentally, what's the difference between this:
var x = a?.b.c;
Assuming that c is of type int.
This is equivalent to
int? x = (a == null) ? null : (int?) a.b.c;
which implies that it throws a NullReferenceException if a is not null but a.b is. You want to use this if a.b is of a nullable reference type, but is never supposed to be null.
And this:
var x = a?.b?.c;
This is the same as
int? x = (a == null) ? null : (a.b == null) ? null : (int?) a.b.c;
except of course that a.b is evaluated only once. The consequence is that no NullReferenceException is thrown in any case. You want to use this if a.b could be null and you want x to be null if it is.

Example:
var method = typeof(Foo).GetMethod("Bar");  // method could be null, but
var methodNameLength = method.?Name.Length; // method.Name should never be null
May 21, 2014 at 7:28 AM
Timwi wrote:
This is equivalent to
int? x = (a == null) ? null : (int?) a.b.c;
which implies that it throws a NullReferenceException if a is not null but a.b is. You want to use this if a.b is of a nullable reference type, but is never supposed to be null.


I think you're assuming left-associativity of the ?. operator rather than the short-circuiting behavior described in the opening post.
May 21, 2014 at 10:19 AM
I think you're assuming left-associativity of the ?. operator rather than the short-circuiting behavior described in the opening post.
No, I’m not. This is the short-circuiting semantics. If a is null, the operator short-circuits by returning null immediately. The (less useful) “left-associative” semantics would be
TypeOfB tmp = (a == null) ? null : a.b;
int? x = (tmp == null) ? null : tmp.c;
May 21, 2014 at 10:48 AM
Nice explanation Timwi,

I'm in favor of short-circuiting over left-associative but I think will be to complicated and subtle for the average C# because it's implicit when the expression ends.

We'll be explaining the feature till the end of time...

Again, won't be better to give it more power to lambdas?
  • by having a sorter syntax for lambdas with just one parameter:
a.Try(t=>t.b.c)
a.Try(@.b.c)  //sorter syntax
  • and maybe even being able to compile them inline as blocks, so there are no performance penalties.
a.Try(t=>t.b.c)
//Gets compiled to 
(var tmp = a) == null ? null : tmp.b.c; 
That will allow non-dot expressions like
a.Try(@.b.c + 1)
And non-null default values like MarkSmeltzer wants
person.Try(@.Name ?? "No name", "No person")
And the feature is more general allowing other uses like:
PropertyInfo pi = entity.GetPropertyInfo(@.Name)

entities.Where(@.Name == "John").Select(@.Surname)
And other interesting blocks methods:
entities.Foreach(@.Name = "John")  //  Foreach using lambdas with  no run-time performance penalty! 

(a+b+c).Let(@ * @)  // (a + b + c) * (a + b + c), catch a sub expression for using it more than once. 

var person = GetPerson().Do(@.IsUsed = true);   // apply an Action to value and return the modified value, without run-time performance
It's a pity that the Roslyn source code has no LINQ whatsoever because is slow...
May 21, 2014 at 10:58 AM
Olmo, I’ve tried to explain to you multiple times that your @ syntax is highly ambiguous and cannot be parsed by a deterministic parser in reasonable time. You continue to refuse to understand this and continue to brag about this idea of yours despite it being an obvious no-go. Please stop it. It is distracting from the discussion of the feature at hand and does not contribute anything but noise to the thread.
May 21, 2014 at 11:29 AM
Olmo wrote:
PropertyInfo pi = entity.GetPropertyInfo(@.Name)

entities.Where(@.Name == "John").Select(@.Surname)
Why do you want to make lazy evaluation look like eager one? Just saving a few characters is not a very good reason for sacrificing readability.
May 21, 2014 at 2:00 PM
Timwi wrote:
Olmo, I’ve tried to explain to you multiple times that your @ syntax is highly ambiguous and cannot be parsed by a deterministic parser in reasonable time. You continue to refuse to understand this and continue to brag about this idea of yours despite it being an obvious no-go. Please stop it. It is distracting from the discussion of the feature at hand and does not contribute anything but noise to the thread.
It's not ambiguous, Scala does it: http://roslyn.codeplex.com/discussions/541330 look at the answer from eldritchconundrum.
May 21, 2014 at 2:12 PM
junyoung wrote:
Olmo wrote:
PropertyInfo pi = entity.GetPropertyInfo(@.Name)

entities.Where(@.Name == "John").Select(@.Surname)
Why do you want to make lazy evaluation look like eager one? Just saving a few characters is not a very good reason for sacrificing readability.
Its not about eager vs lazy, is about compiling a lambda as a method or inline code. In order to make low-level efficient code maybe laziness should be considered in some scenarios though.

This is a complex feature however, requiring meta programming and syntax tree manipulation.

My point is that, while I definitely will use the Null propagating operator, in fact I added a request for it in Microsoft Connect like four years ago, the implementation looks too complex to explain because of the short-circuit vs left-associative issues.

Also, is too specific not allowing valid (but not that common) cases like the one I explain.

Maybe is better to consider solving more general features before making C# even more complex.
May 21, 2014 at 5:41 PM
Timwi wrote:
I think you're assuming left-associativity of the ?. operator rather than the short-circuiting behavior described in the opening post.
No, I’m not. This is the short-circuiting semantics. If a is null, the operator short-circuits by returning null immediately. The (less useful) “left-associative” semantics would be
TypeOfB tmp = (a == null) ? null : a.b;
int? x = (tmp == null) ? null : tmp.c;
Yep, you're right.

Still, though it's less useful/forgiving, I like the idea that the language encourages you not to mix and match ?. and . operators in a single statement. A statement like a?.b?.c is way more clear than a statement like a?.b.c. As the opening post suggests, there are two camps for what the expected behavior should be in the latter case, but in the former case there's no ambiguity. Why not encourage the former?
May 21, 2014 at 9:31 PM
gzak wrote:
Still, though it's less useful/forgiving, I like the idea that the language encourages you not to mix and match ?. and . operators in a single statement. A statement like a?.b?.c is way more clear than a statement like a?.b.c. As the opening post suggests, there are two camps for what the expected behavior should be in the latter case, but in the former case there's no ambiguity. Why not encourage the former?
The reason is that c# is a strict language not a forgiving one.

In JavaScript or visual basic the idea is to try to keep the program running in the unexpected situations.

In c# the culture is to fail fast by asserting for the unexpected situations.

If you write a?.b.c you're stating that a is allowed to be null but not b, clearly communicating intent. Using left-associativity you're forced to write a?.b?.c creating uncertainty on whether b could be null or not. Having no non-nullable reference types will communicate this better though.

The problem is that the feature requires some parenthesis to be understood at the beginning: a?.b.c is really something like a?(.b.c) but this syntax will probably cause ambiguities with conditional operator.
May 21, 2014 at 9:50 PM
Edited May 21, 2014 at 9:57 PM
The real problem as I see it is programmers want to say:
var o =? Some.Long.Reference.Value;
and get a null value if any reference in the reference chain is null.

While I understand the convenience of not needing to code the null checks, I am concerned that using the capability will hide bugs and end up costing more in diagnostic time than the savings in coding time.
May 21, 2014 at 11:27 PM
Olmo wrote:
It's not ambiguous, Scala does it: http://roslyn.codeplex.com/discussions/541330 look at the answer from eldritchconundrum.
You never give up, do you?... This forum is about C#, not Scala. Scala is an entirely different and separate language. You are suggesting it as a feature for C#, therefore for your proposal to be taken seriously you need to provide a precise specification on how the feature would fit into the existing C# language. You have not done that, and I have tried to explain to you that it is more complex than you apparently imagine it to be, and simply pointing at a wholly different language that has a vaguely similar feature is not going to take that complexity away or give your proposal any more credence.
May 21, 2014 at 11:44 PM
MarkSmeltzer wrote:
Secondly, I would recommend that the operator "?." have an optional ":" extension that allows overriding the default null value. Here is an example of what that would look like:
var name = customer ?.Name : "Missing Name" ?? "Unknown User";
It seems to me that if the ":" is an extension of the "?." operator, then your expression should be evaluated like
var name = (customer ?.Name : "Missing Name") ?? "Unknown User";
in which case I believe you have your strings backwards from what you intend, and your code expansion backwards as well.

If it's too complicated for you to parse, perhaps it isn't a good extension?
May 22, 2014 at 12:08 AM
Haha. Good jab.

You are correct that I had it reversed - I can see the mistake now that you point it out, and since it was arbitrary code to demonstrate a point I simply didn't double check it.

May 22, 2014 at 7:07 AM
Olmo wrote:
junyoung wrote:
Olmo wrote:
PropertyInfo pi = entity.GetPropertyInfo(@.Name)

entities.Where(@.Name == "John").Select(@.Surname)
Why do you want to make lazy evaluation look like eager one? Just saving a few characters is not a very good reason for sacrificing readability.
Its not about eager vs lazy, is about compiling a lambda as a method or inline code. In order to make low-level efficient code maybe laziness should be considered in some scenarios though.
Why don't you use query expressions:
from entity in entities
where entity.Name == "John"
select entity.Surname;
It's much cleaner than @ syntax.
May 22, 2014 at 1:31 PM
Timwi wrote:
Olmo wrote:
It's not ambiguous, Scala does it: http://roslyn.codeplex.com/discussions/541330 look at the answer from eldritchconundrum.
You never give up, do you?... This forum is about C#, not Scala. Scala is an entirely different and separate language. You are suggesting it as a feature for C#, therefore for your proposal to be taken seriously you need to provide a precise specification on how the feature would fit into the existing C# language. You have not done that, and I have tried to explain to you that it is more complex than you apparently imagine it to be, and simply pointing at a wholly different language that has a vaguely similar feature is not going to take that complexity away or give your proposal any more credence.
Hi Timwi. Don't get emotional about the topic. We're just proposing C# features, let's keep a healthy environment.

I've read your comments in http://roslyn.codeplex.com/discussions/541330 and you expressed some valid concerns. I answered to the first one, but I forgot the second one. I will try to do what you suggest: read more carefully the C# Spec and propose a more carefully designed feature. I actually tried to fork the source code but I had some problems adding new syntax (https://roslyn.codeplex.com/discussions/542102) and VS didn't stopped crashing.

I think however that the fact that Scala can do it is a strong point for being able to come up with a non-ambiguous grammar/binder. I don't see fundamental differences between Scalar in C# in this particular point, tell me if you do. I've heard Scala compiler is slower... maybe that's on the reasons?

Hopefully if the technical problems get solved you will like the idea.

I think no C# feature is an island, and shorter lambdas could make Null propagating operator less useful, so its worth considering it before adding this specific and hard to grasp language feature. Once that is done, let's move the discussion about sort lambdas to where they should be: http://roslyn.codeplex.com/discussions/541330
May 22, 2014 at 1:41 PM
junyoung wrote:
Why don't you use query expressions:
from entity in entities
where entity.Name == "John"
select entity.Surname;
It's much cleaner than @ syntax.
It's much cleaner for the methods supported on query syntax (Select, SelectMany, Where, Join, GroupBy and OrderBy) but there are many other methods that take lambdas that are not in this G6.

Speaking of query syntax, if we rename my Try method by SelectMany we could use query syntax to fake Null propagating operator, pretending Haskell do notation:
var name = Customer.Address?.Country.Name;  //Using Null propagating operator

var name = from a in Customer.Address //Using query syntax and abUsing SelectMany
                  from n in a.Country.Name
                  select n;

var name = (var temp = Customer.Address) == null ? null : temp.Country.Name;  //Using declaration expressions
Of course the problem is that now the 'normal' SelectMany will be hard to use because the ambiguities everywhere. Just a crazy idea.
May 27, 2014 at 4:43 PM
How about instead of a accessor operator, you create a unary operator?
var name = ?(Customer.Address.Country.Name);
This is concise and is somewhat descriptive of the behavior.
May 27, 2014 at 4:51 PM
msauper wrote:
How about instead of a accessor operator, you create a unary operator?
var name = ?(Customer.Address.Country.Name);
This is concise and is somewhat descriptive of the behavior.
How about this one:
var name = null(Customer.Address.Country.Name);
It's similar in usage to checked/unchecked expressions.
May 27, 2014 at 5:09 PM
I second the idea to change the syntax. With the explicit block there is no syntactic ambiguity. While a?.b.c can be possibly understood as both a?.(b.c) and (a?.b).c, the meaning of the syntax with parentheses cannot be misinterpreted.
May 27, 2014 at 5:32 PM
VladD wrote:
I second the idea to change the syntax. With the explicit block there is no syntactic ambiguity. While a?.b.c can be possibly understood as both a?.(b.c) and (a?.b).c, the meaning of the syntax with parentheses cannot be misinterpreted.
I like that idea; it's somewhat analogous to the unchecked operator. Further, it avoids any parsing confusion older tools might have with code that uses ? without : [older tools wouldn't be able to recognize what null(this.that.theother) means, but could probably parse it as an invocation of a function called null--far less problematic than an attempt to parse an expression using ?..
May 27, 2014 at 5:38 PM
How would you express a.b.c?.d.e with the proposed syntax?
May 27, 2014 at 6:03 PM
MgSam wrote:
How would you express a.b.c?.d.e with the proposed syntax?
Perhaps a.b.null(c.d).e?
May 27, 2014 at 7:07 PM
I am uncomfortable using some type of nullable operator within a complex dereferencing expression. I think this only makes sense when the entire reference chain is included in the expression. Does a.b.c?.d.e mean that it's ok for c,d, or e to be null, but a and b cannot be null?

I think that you would code the following.
var o = a.b.c;
var val = ?(o.d.e); // or null(o.d.e)
May 27, 2014 at 7:22 PM
supercat wrote:
Perhaps a.b.null(c.d).e?
a.b.null(c.d).e is ambiguous, more verbose, and forces you to write your code inside-out.

msauper wrote:
I am uncomfortable using some type of nullable operator within a complex dereferencing expression. I think this only makes sense when the entire reference chain is included in the expression. Does a.b.c?.d.e mean that it's ok for c,d, or e to be null, but a and b cannot be null?

I think that you would code the following.
var o = a.b.c;
var val = ?(o.d.e); // or null(o.d.e)
This partially defeats the purpose no? You're still assigning things to temporaries yourself rather than having the compiler do it for you. And you're writing your code inside out.
  • Does ?(o.d.e) mean o?.d?.e or o?.d.e?
  • How would you write a.b.c?.d.e?.f? That seems like it would be quite a mess, no?
The proposed alternate syntax is both more ambiguous, and more verbose.

I don't think ?. is any more ambiguous than any other operator. You just have to understand its semantics to use it properly.
May 27, 2014 at 7:30 PM
Edited May 27, 2014 at 7:34 PM
My suggestion was not really trying to address any ambiguity of the operator. I was trying to consider the usability of the concept.

my suggestion of the ?(expression) syntax was to have any first-order null reference exceptions to return null as the final value of the expression. I am using first-order to mean any value that is part of the expression. Nested null value exceptions would still be propagated.

I also do not think that this concept would/should be used in main-line logic where the distinction of whether a and b are not null, but c, d, and e are allowed to be null is important. It strikes me that this is more properly used in error conditions where you do not want to add a lot of guard logic just to be able to print out a diagnostic.
May 27, 2014 at 7:41 PM
So the ?() operator would catch NullReferenceExceptions? That seems really inefficient.

I thought the idea was the ?(a.b.c) was equivalent to a?.b?.c. The use case for this seems narrow. You need at least 3 dereferences just to break even on the number of characters: ?(a.b.c.d)/a?.b?.c?.d You'd almost never want to use it in an expression that mixed . and ?., and by itself it does not have the expressiveness of ?. to be a replacement syntax.

I vote against this feature/alternate syntax suggestion.
May 27, 2014 at 8:02 PM
Edited May 27, 2014 at 8:03 PM
msauper wrote:
I am uncomfortable using some type of nullable operator within a complex dereferencing expression. I think this only makes sense when the entire reference chain is included in the expression. Does a.b.c?.d.e mean that it's ok for c,d, or e to be null, but a and b cannot be null?
The code a.b.c?.d.e is resilient against c being null, but will cause a NullReferenceException if any of a, b, or d are null.
May 27, 2014 at 8:33 PM
Edited May 27, 2014 at 8:42 PM
?. has basically the same purpose as strlcpy/strlcat in C: it helps hide bugs. Given the following code:
var name = a?.b?.c;
and if name is evaluated null, that can be a totally unexpected situation that you have no idea where null came from! You still have to null-check a, b, and c:
var name = a?.b?.c;
if (name == null) {
  if (a == null)
    a = new ClassA();
  else if (a.b == null)
    a.b = someReasonableValueNotNull;
}
May 27, 2014 at 8:45 PM
junyoung wrote:
?. has basically the same purpose as strlcpy/strlcat in C: it helps hide bugs. Given the following code:
var name = a?.b?.c;
and if name is evaluated null, that can be totally an unexpected situation that you don't know where null came from! You still have to null-check a, b, and c anyway:
var name = a?.b?.c;
if (name == null) {
  if (a == null)
    Init(a);
  else if (a.b == null)
    Init(a.b);
}
In which case you wouldn't want to use the null propagating operator, but that scenario isn't as common as just wanting to collapse down the expression and not have it throw a NullReferenceException if a happened to be null. It's not like that would become the only method through which you'd be able to null check.
May 27, 2014 at 8:46 PM
junyoung wrote:
that can be totally an unexpected situation that you don't know where null came from!
The use case for the ?. operator is when you don't care where the null came from, which in my experience is far more common.

When I say
Person a;
var bestFriendsPetName = a.Friends.FirstOrDefault()?.Pets.FirstOrDefault()?.Name ?? "None";
I don't want to worry about the case where the person has no friends or his best friend has no pets, all I care about is getting to the end result without lots of boilerplate null checks.
May 27, 2014 at 10:04 PM
MgSam wrote:
junyoung wrote:
that can be totally an unexpected situation that you don't know where null came from!
The use case for the ?. operator is when you don't care where the null came from, which in my experience is far more common.

When I say
Person a;
var bestFriendsPetName = a.Friends.FirstOrDefault()?.Pets.FirstOrDefault()?.Name ?? "None";
I don't want to worry about the case where the person has no friends or his best friend has no pets, all I care about is getting to the end result without lots of boilerplate null checks.
Then what can you do with "None"? If you display it on the screen it would be something like:

Anders' best friend's favorite pet's name: None

Quite ambiguous message made possible by use of ?.. I would call ?. an ambiguity operator. :-)

And the above message is almost useless, since people are interested in who's the Person's best friend and who has what pet. So the better message would be:

Anders' best friend Doug has no pets

This is not possible if you use ?..

Another case is when Person a is passed as a method parameter:
string GetBestFriendsPetName(Person a) {
    return a?.Friends.FirstOrDefault()?.Pets.FirstOrDefault()?.Name ?? "None";
}
Use of ?. after a easily hides a bug that null is passed instead of an instance of Person. So when you get "None" as a result of calling this method, it's pretty useless since you don't know if the person has no friends, his best friend has no pets, or even the person doesn't exist.
Jun 3, 2014 at 6:45 PM
Apologies if this has already been answered, but this is a very long thread with a lot of intricate details

I can definitely see uses for this (especially with short-circuiting) - however this leaves one large question:

Can you write the following?

public event MyHandler OnMyEvent;

...

OnMyEvent?.();

The reason for this is that it avoid a two line step for a simple task that I repeat a LOT - "If there are any event subscribers, publish an event to them"

if (OnMyEvent != null)
OnMyEvent();

As far as syntax goes - it would probably look better using the indexor version:

OnMyEvent?(); rather than OnMyEvent?.();
Jun 8, 2014 at 9:24 PM
ControlFlow wrote:
OMG, Mads, are you serious??!?!

So now we will have a language where naively introducing variable:
return a?.b.c;
will change the meaning of the program?
var t = a?.b;
return t.c
That does indeed seem to be the case. I just tried this scenario on the VS 14 CTP:
class A
{
    public string B { get; } = "B";
}

class Program
{
    static void Main(string[] args)
    {
        A a = null;
        var res1 = a?.B.Length;
        var temp = a?.B;
        var res2 = temp.Length;
    }
}
res1 gets null assigned and the evaluation of the res2 RHS results in a NullReferenceException. Eww! Just eww!

I've run into stuff like this with PowerShell and it drives me bonkers. This has been fixed in PowerShell v3 but check this out in V1/V2. The following will not execute the loop body because there is no dir as "no-such-dir":
foreach ($item in (ls no-such-dir)) { ... }
However innocently switch the script to this and the behavior changes:
$items = ls no-such-dir
foreach ($item in $items) { ... }
This does execute the loop body once because when the empty set is assigned to $items, PowerShell assigns $null to $items. The PowerShell foreach statement will execute the loop body once for a scalar value and in V1/V2 that scalar value could be $null. Please don't do this sort of thing to C#. IMO the current C# "?." implementation, as shown above, violates the Principle of Least Surprise.
Jun 8, 2014 at 9:33 PM
r_keith_hill wrote:
IMO the current C# "?." implementation, as shown above, violates the Principle of Least Surprise.
It has been discussed many times here that the current semantics of ?. operation is the desired one.
As well, it has been pointed out many times that the current syntax is highly misleading, and is going to be a source of numerous errors, and definitely doesn't drive the language user into the Pit Of Success.
I think, someone has yet to come up with a proper, better, unambiguous syntax.
Suggestions, anyone?
Jun 8, 2014 at 10:33 PM
Edited Jun 8, 2014 at 11:03 PM
VladD wrote:
Suggestions, anyone?
Sure. It's better to not add a flawed feature. Somehow we have been getting by for 12 years without this. :-)

Honestly, the number of proposed features that appear a bit "wobbly" so far makes me a bit nervous. I hope we don't look back on this release as the release of C# that "jumped the shark".
Jun 8, 2014 at 11:09 PM
r_keith_hill wrote:
Sure. It's better to not add a flawed feature. Somehow we been getting by for 12 years without this. :-)
Well, cutting the features is not going to be warmly accepted by the community, so let's try to suggest something more constructive.

Ok, as I asked for ideas, I have to make a suggestion. How about a.[b.c] with the same semantics as the current a?.b.c (i.e., a != null ? a.b.c : null)? This seems to be expressive enough.
Jun 9, 2014 at 2:07 AM
r_keith_hill wrote:
ControlFlow wrote:
OMG, Mads, are you serious??!?!

So now we will have a language where naively introducing variable:
return a?.b.c;
will change the meaning of the program?
var t = a?.b;
return t.c
That does indeed seem to be the case. I just tried this scenario on the VS 14 CTP:
class A
{
    public string B { get; } = "B";
}

class Program
{
    static void Main(string[] args)
    {
        A a = null;
        var res1 = a?.B.Length;
        var temp = a?.B;
        var res2 = temp.Length;
    }
}
I'm not understanding the problem. That code you highlight works exactly the way I would expect it to. It seems like the argument here is essentially, "I don't understand this feature, I expect it to work X way but in fact it works Y way. Therefore the feature is poorly designed."

The ?. operator is short circuiting. Once you understand that, there should be no surprises. Your argument is akin to saying that this is surprising:
public bool AlwaysTrue()
{
    Console.WriteLine("foo");
    return true;
}

if(true || AlwaysTrue())
    Console.WriteLine("bar"); 
//Simply prints "bar"

var a = true;
var b = AlwaysTrue();
var c = a || b;
if(c)
    Console.WriteLine("bar");
//Prints "foo" and "bar"
Jun 9, 2014 at 5:51 AM
Edited Jun 9, 2014 at 5:52 AM
VladD wrote:
r_keith_hill wrote:
Sure. It's better to not add a flawed feature. Somehow we been getting by for 12 years without this. :-)
Well, cutting the features is not going to be warmly accepted by the community, so let's try to suggest something more constructive.

Ok, as I asked for ideas, I have to make a suggestion. How about a.[b.c] with the same semantics as the current a?.b.c (i.e., a != null ? a.b.c : null)? This seems to be expressive enough.
Nice - I actually rather like this square bracket call as it helps to make it clear that what's in the brackets is what remains after the conditional check (the question mark is a little subtle)
Jun 9, 2014 at 5:58 AM
ControlFlow wrote:
So now we will have a language where naively introducing variable:
return a?.b.c;
will change the meaning of the program?
var t = a?.b;
return t.c
Then don't be "naive" when introducing variables! The language is already chock full of places where naivety will get it wrong...
return a + b * c;
==>
var t = a + b;
return t * c;
or this
var x = new[] {null, "hello"};
==>
var t = null;
var x = new[] {t, "hello"};
In the case of ?. there's a clean non-naive way to introduce the explaining variable:
return a?.b.c
==>
var t = a?.b; return t.c;  // NOT THIS
var t = a?.b; return t?.c;  // USE THIS INSTEAD
Jun 9, 2014 at 4:02 PM
MgSam wrote:
The ?. operator is short circuiting. Once you understand that, there should be no surprises. Your argument is akin to saying that this is surprising:
public bool AlwaysTrue()
{
    Console.WriteLine("foo");
    return true;
}

if(true || AlwaysTrue())
    Console.WriteLine("bar"); 
//Simply prints "bar"

var a = true;
var b = AlwaysTrue();
var c = a || b;
if(c)
    Console.WriteLine("bar");
//Prints "foo" and "bar"
That seems to be not a very good example, since
var a = true;
if(a || AlwaysTrue())
    Console.WriteLine("bar");
and
var a = true;
var temp = a || AlwaysTrue();
if(temp)
    Console.WriteLine("bar");
have the same result, but
var res1 = a?.B.Length;
and
var temp = a?.B;
var res2 = temp.Length;
don't.

It's no doubt that the current design of ?. is flawed. The left associative version of ?. is better in that regard, but it has another problem.

Conclusion: ?. shouldn't be part of the C# 6.0. We've been doing well many years without it.
Jun 9, 2014 at 6:58 PM
junyoung wrote:
That seems to be not a very good example, since [code examples] have the same result, but...
The aforementioned variable substitution doesn't always work with the struct "direct" member access operator either (which in C#, unlike C++, looks just like the rvalue/indirect member access operator). Some people view that as a sign that structures are evil; others view it as a sign that programmers shouldn't blindly expect the variable substitutions will always be valid. As for myself, I view it as a sign that C# should have had separate -> and . tokens [both structures and classes could define methods which use both operators; . would invoke a method which accepts this as a ref, and -> would invoke a method that takes this as a value].
Jun 9, 2014 at 11:29 PM
We've been doing well many years without it.
Can we please stop saying that? You’re free to stick to C# 4.0 forever and shut yourself out from all progress. Please don’t hold us back.
Jun 9, 2014 at 11:33 PM
Timwi wrote:
We've been doing well many years without it.
Can we please stop saying that? You’re free to stick to C# 4.0 forever and shut yourself out from all progress. Please don’t hold us back.
+1 Thank you
Jun 10, 2014 at 3:19 AM
It's really curious that Swift does practically the same thing with practically the same syntax. Both the ?. operator (with ?[] and ?() variants for indexers and method invocation), and the operation is short-circuiting. While I don't advocate that C# copy Swift it seems to me to be a vote of confidence in that direction.

Other interesting tidbits in Swift is the ability to treat the evaluation as a conditional. In C# that might look something like:
if (var length = employee?.Name?.Length) // length evaluated as type int, not Nullable<int>
{
    Console.WriteLine($"The length of the employee's name is {length}.");
}
else
{
    Console.WriteLine("Either the employee or the employee's name is null!");
}
They also have a "forced unwrapping" operator, which I can only somewhat compare to the Nullable<T>.Value property:
int? x = 42;
int y = x!;
Jun 10, 2014 at 9:43 AM
lwischik wrote:
In the case of ?. there's a clean non-naive way to introduce the explaining variable:
return a?.b.c
==>
var t = a?.b; return t.c;  // NOT THIS
var t = a?.b; return t?.c;  // USE THIS INSTEAD
And now it's not the same behavior when a.b is null.

The problem is that ?. looks like ., suggesting left-associativity, making it intuitive to believe that this refactoring would be valid.
Maybe a?b would be a bit better in that regard, but that would be too ambiguous for C#.
The a.[b.c] syntax solves the problem, a?[b.c] would work too, but they look strange, especially for the main use case, which is simply a?.b.
The language is already chock full of places where naivety will get it wrong...
Saldy I think there is no choice but to add another one.
Jun 10, 2014 at 9:55 AM
Halo_Four wrote:
It's really curious that Swift does practically the same thing with practically the same syntax. Both the ?. operator (with ?[] and ?() variants for indexers and method invocation), and the operation is short-circuiting. While I don't advocate that C# copy Swift it seems to me to be a vote of confidence in that direction.
nil and null are different. In Swift, instances of reference types are guaranteed to be non-nil. ?. operator is also different from the proposed C# ?.: it's left-associative and non-short-circuiting.

Now i'm curious about where the (bad) idea of short-circuiting ?. came from. At least in two languages that have ?. operator, Groovy and Swift, it's left-associative and non-short-circuiting.
Jun 10, 2014 at 1:01 PM
junyoung wrote:
Now i'm curious about where the (bad) idea of short-circuiting ?. came from. At least in two languages that have ?. operator, Groovy and Swift, it's left-associative and non-short-circuiting.
Here is a short summary of previous debate.

Assuming left-associative non-short-circuiting, a?.b.c is never useful, only a?.b?.c is.
The idea is that we want to use a?.b.c to mean "I want to get null if a is null, but I want to get a NullRefException when a is not null but a.b is".
That makes ?. useful in more cases, and it avoids encouraging the a?.b?.c style which would risk swallowing errors silently.
This comes at the cost of a loss of intuitiveness in refactoring.
Most people in this thread seem to consider than being able to use a?.b.c is well worth that extra complexity.

In Swift and Groovy, I suppose that either they did not think of using a?.b.c this way, either they decided it was not worth that cost.
Jun 10, 2014 at 2:16 PM
junyoung wrote:
Halo_Four wrote:
It's really curious that Swift does practically the same thing with practically the same syntax. Both the ?. operator (with ?[] and ?() variants for indexers and method invocation), and the operation is short-circuiting. While I don't advocate that C# copy Swift it seems to me to be a vote of confidence in that direction.
nil and null are different. In Swift, instances of reference types are guaranteed to be non-nil. ?. operator is also different from the proposed C# ?.: it's left-associative and non-short-circuiting.

Now i'm curious about where the (bad) idea of short-circuiting ?. came from. At least in two languages that have ?. operator, Groovy and Swift, it's left-associative and non-short-circuiting.
According to the Swift documentation it sounds right-associative (emphasis mine):
Postfix expressions that contain an optional-chaining expression are evaluated in a special way. If the optional-chaining expression is nil, all of the other operations in the postfix expression are ignored and the entire postfix expression evaluates to nil. If the optional-chaining expression is not nil, the value of the optional-chaining expression is unwrapped and used to evaluate the rest of the postfix expression. In either case, the value of the postfix expression is still of an optional type.
Swift Expressions
You are correct in that nil doesn't quite mean null but it's as close as Swift gets as the language has no concept of null, unlike Objective-C. nil is the only way to represent the absence of a value.
Jun 10, 2014 at 2:23 PM
Edited Jun 10, 2014 at 2:28 PM
eldritchconundrum wrote:
junyoung wrote:
Now i'm curious about where the (bad) idea of short-circuiting ?. came from. At least in two languages that have ?. operator, Groovy and Swift, it's left-associative and non-short-circuiting.
Here is a short summary of previous debate.

Assuming left-associative non-short-circuiting, a?.b.c is never useful, only a?.b?.c is.
The idea is that we want to use a?.b.c to mean "I want to get null if a is null, but I want to get a NullRefException when a is not null but a.b is".
That makes ?. useful in more cases, and it avoids encouraging the a?.b?.c style which would risk swallowing errors silently.
This comes at the cost of a loss of intuitiveness in refactoring.
Most people in this thread seem to consider than being able to use a?.b.c is well worth that extra complexity.

In Swift and Groovy, I suppose that either they did not think of using a?.b.c this way, either they decided it was not worth that cost.
Unless I am reading Swift's documentation completely wrong, they do appear to have implemented the short-circuiting version. I know Oxygene used to be left-associative but after watching Roslyn's debates they decided to switch to short-circuiting.

Honestly, both approaches are with peril in that the target audience is not likely those who would understand the nuance and regardless of implementation if you are referencing a few members deep and those members are reference types you'd want to chain the operator anyway as even if in a?.b.c if a is not null but b is null then in both implementations you're going to get a NullReferenceException.

I do think that it's important to mention that when the C# team proposed left-associative they intended that attempting to chain with the . operator would be a compiler error, so technically a?.b.c wouldn't be valid. Honestly, that might be safer, even if it means lots of extra question marks everywhere.
Jun 10, 2014 at 3:02 PM
Actually here’s another reason for the short-circuiting behaviour which until now has not been mentioned. Think about what you want the following to mean:
    MyObject?.Foo();
I think we can all agree that we want this to mean “If MyObject is null, invoke that member, otherwise don’t”. With the short-circuiting semantics, this is indeed what it does, in all cases.

With the non-short-circuiting behaviour, i.e. the “left-associative”, this is a subtle trap in the case where Foo is not a method, but a property or field whose type is a delegate. In such a case, the left-associative behaviour would throw NullReferenceException if MyObject is null, even though you used ?.. I think we can all agree that this would be highly unexpected and would take a long time to debug.

To make matters worse, now consider what should happen when MyObject is of type dynamic. With the “left-associative” behaviour, the dynamic runtime now needs to exhibit starkly different behaviour depending on whether Foo is a delegate property or a method.

Do not try to argue this away by saying this case is rare. It is clearly valid code and needs to work correctly.
Jun 10, 2014 at 3:28 PM
Edited Jun 10, 2014 at 3:28 PM
Timwi wrote:
Actually here’s another reason for the short-circuiting behaviour which until now has not been mentioned.
And another reason... We often naturally write code like this:
string s;
if (customer != null)
{
    s = customer.address.city;
}
else
{
    s = null;
}
The straightforward way to write it is var s = customer?.address.city.

The ?. operator corresponds to a null-check that I used to write, no more, no less.


If you gave me `var s = customer?.address?.city" and I didn't know (and didn't care about) the weirdnesses of left associativity then I'd automatically assume it meant multiple null-checks,
string s;
if (customer != null)
{
    if (customer.address != null)
    {
        s = customer.address.city;
    }
    else
    {
        s = null;
    }
else
{
    s = null;
}
Jun 10, 2014 at 3:59 PM
lwischik wrote:
Timwi wrote:
Actually here’s another reason for the short-circuiting behaviour which until now has not been mentioned.
And another reason... We often naturally write code like this:
string s;
if (customer != null)
{
    s = customer.address.city;
}
else
{
    s = null;
}
The straightforward way to write it is var s = customer?.address.city.

The ?. operator corresponds to a null-check that I used to write, no more, no less.


If you gave me `var s = customer?.address?.city" and I didn't know (and didn't care about) the weirdnesses of left associativity then I'd automatically assume it meant multiple null-checks,
string s;
if (customer != null)
{
    if (customer.address != null)
    {
        s = customer.address.city;
    }
    else
    {
        s = null;
    }
else
{
    s = null;
}
That makes sense, although part of me still thinks that perhaps there should be a warning for address.city if address is not a value type since that should still result in a NullReferenceException.
Jun 10, 2014 at 5:11 PM
Edited Jun 10, 2014 at 5:23 PM
Halo_Four wrote:
junyoung wrote:
Halo_Four wrote:
It's really curious that Swift does practically the same thing with practically the same syntax. Both the ?. operator (with ?[] and ?() variants for indexers and method invocation), and the operation is short-circuiting. While I don't advocate that C# copy Swift it seems to me to be a vote of confidence in that direction.
nil and null are different. In Swift, instances of reference types are guaranteed to be non-nil. ?. operator is also different from the proposed C# ?.: it's left-associative and non-short-circuiting.

Now i'm curious about where the (bad) idea of short-circuiting ?. came from. At least in two languages that have ?. operator, Groovy and Swift, it's left-associative and non-short-circuiting.
According to the Swift documentation it sounds right-associative (emphasis mine):
Postfix expressions that contain an optional-chaining expression are evaluated in a special way. If the optional-chaining expression is nil, all of the other operations in the postfix expression are ignored and the entire postfix expression evaluates to nil. If the optional-chaining expression is not nil, the value of the optional-chaining expression is unwrapped and used to evaluate the rest of the postfix expression. In either case, the value of the postfix expression is still of an optional type.
Swift Expressions
That doesn't necessarily mean it to be right associative.

According to another part of the book:
if let johnsStreet = john.residence?.address?.street {
and here as well:
if let buildingIdentifier = john.residence?.address?.buildingIdentifier() {
and even longer chaining:
if let upper = john.residence?.address?.buildingIdentifier()?.uppercaseString {
It seems that you should always use ?. for optional chaining.
Jun 10, 2014 at 5:37 PM
junyoung wrote:
Halo_Four wrote:
junyoung wrote:
Halo_Four wrote:
It's really curious that Swift does practically the same thing with practically the same syntax. Both the ?. operator (with ?[] and ?() variants for indexers and method invocation), and the operation is short-circuiting. While I don't advocate that C# copy Swift it seems to me to be a vote of confidence in that direction.
nil and null are different. In Swift, instances of reference types are guaranteed to be non-nil. ?. operator is also different from the proposed C# ?.: it's left-associative and non-short-circuiting.

Now i'm curious about where the (bad) idea of short-circuiting ?. came from. At least in two languages that have ?. operator, Groovy and Swift, it's left-associative and non-short-circuiting.
According to the Swift documentation it sounds right-associative (emphasis mine):
Postfix expressions that contain an optional-chaining expression are evaluated in a special way. If the optional-chaining expression is nil, all of the other operations in the postfix expression are ignored and the entire postfix expression evaluates to nil. If the optional-chaining expression is not nil, the value of the optional-chaining expression is unwrapped and used to evaluate the rest of the postfix expression. In either case, the value of the postfix expression is still of an optional type.
Swift Expressions
Hmm, that seems contrary to the other part of the book:
if let johnsStreet = john.residence?.address?.street {
and here as well:
if let buildingIdentifier = john.residence?.address?.buildingIdentifier() {
and even longer chaining:
if let upper = john.residence?.address?.buildingIdentifier()?.uppercaseString {
Yes, that is the case because in their example the address property of Residence is an Optional<Address> and the buildingIdentifier() method of Address also returns an Optional<String>. You would be required to use either ? or ! in order to dereference the properties. If the code example were as follows instead:
let street = john.residence?.address!.street
If residence is nil the code would succeed and the result would be nil, but if residence is not nil but address is nil that would result in a runtime error equivalent to a NullReferenceException.

Take another example:
let name = john.residence?[0].name
In this case if the residence property returns nil it immediately bails with an Optional<String> with the value of nil. Because the subscript method of the Residence type does not return an not optional and the name property of the Room type is not optional you aren't required (or even allowed) to use the optional chaining operator. If Swift ?. was left-associative, the result of the subscript would be implicitly Optional<Room> which would require further chaining, and that is not the case.
Jun 10, 2014 at 5:41 PM
Halo_Four wrote:
That makes sense, although part of me still thinks that perhaps there should be a warning for address.city if address is not a value type since that should still result in a NullReferenceException.
I think there should be no such warning because it's just a usual member access (and it looks exactly like one), so of course it can throw NullReferenceException.

Left-associative null propagating operator in Oxygene was counterintuitive (and disappointing) to me. I strongly vote for the current design (including syntax). It seems the most clear and intuitive to me. In the ControlFlow's "naive variable" example code behaves exactly as expected. And of course a?.b.c is not the same as a.b.c and behaves differently.
Jun 10, 2014 at 5:57 PM
Maybe Swift ?. is a kind of left-associative and short-circuiting operator?

Two simple rules would be sufficient:
  • Each ?. corresponds to a member access operation with a != null check. (left-associative)
  • If one of ?. operations in an expression is nil, the rest of the expression is ignored. (short-circuiting)
Jun 10, 2014 at 6:32 PM
junyoung wrote:
Maybe Swift ?. is a kind of left-associative and short-circuiting operator?

Two simple rules would be sufficient:
  • Each ?. corresponds to a member access operation with a != null check. (left-associative)
  • If one of ?. operations in an expression is nil, the rest of the expression is ignored. (short-circuiting)
That sounds exactly like how the current proposal in Roslyn would work. It does evaluate member access left-to-right, but as soon as the operator applies to a null value it short circuits and immediately returns null.

C#:
var street = user?.address.street;
Swift:
let street = user?.address!.street
In both cases, if user is null/nil then the code will succeed and the result would be null/nil. Again in both cases if user is not null/nil, but if address returns null/nil, you'd get a runtime error attempting to reference the street property.

The big differences are that in Swift only an Optional<T> can be nil and that if you want to unwrap it you must use the ! operator or further chain with the ? operator.
Jun 10, 2014 at 6:44 PM
Quinisext wrote:
Halo_Four wrote:
That makes sense, although part of me still thinks that perhaps there should be a warning for address.city if address is not a value type since that should still result in a NullReferenceException.
I think there should be no such warning because it's just a usual member access (and it looks exactly like one), so of course it can throw NullReferenceException.

Left-associative null propagating operator in Oxygene was counterintuitive (and disappointing) to me. I strongly vote for the current design (including syntax). It seems the most clear and intuitive to me. In the ControlFlow's "naive variable" example code behaves exactly as expected. And of course a?.b.c is not the same as a.b.c and behaves differently.
Indeed, the semantics are correct for the nature of ?. as right-associative (or short-circuiting). My concern remains that the target audience won't understand the nuances of those semantics and I can guarantee you that in the vast majority of situations the developer would have not intended for that expression to potentially throw an exception. Because of that I do think that a warning is appropriate.

If I could borrow a page from Swift I think that a complimentary operator could allow the developer to opt-in to wanting that expression without a warning.
var street = user?.address.street; // compiler warning, if address is null then throws exception
var street = user?.address?.street; // no warning, if address is null then also returns null
var street = user?.address!.street; // no warning, if address is null then throws exception
I don't believe that something like this is without precedent. For example, if within an async method you call a method that returns a Task but do not await that task the compiler emits a warning, which can be dismissed by assigning that Task to a variable.
Jun 10, 2014 at 7:10 PM
Edited Jun 10, 2014 at 7:10 PM
In the vast majority of situations the developer would have not intended for any member access to potentially throw an exception. And this is just another member access.
If one doesn't use await in an async method it's most probably an error. This is not the case for a member access. It's just how it works in C#: one decides whether it's safe to make a member access without null-checking or not.
Jun 10, 2014 at 7:19 PM
Halo_Four wrote:
junyoung wrote:
Maybe Swift ?. is a kind of left-associative and short-circuiting operator?

Two simple rules would be sufficient:
  • Each ?. corresponds to a member access operation with a != null check. (left-associative)
  • If one of ?. operations in an expression is nil, the rest of the expression is ignored. (short-circuiting)
That sounds exactly like how the current proposal in Roslyn would work. It does evaluate member access left-to-right, but as soon as the operator applies to a null value it short circuits and immediately returns null.
Not exactly the same. For example, in the current design of C# vNext
var x = a?.b.c.d;
is a short-hand for
var x = a?.b?.c?.d;
They are different in Swift, though.

Here's an explanation from lwischik:
return a?.b.c
==>
var t = a?.b; return t.c; // NOT THIS
var t = a?.b; return t?.c; // USE THIS INSTEAD
I think what's more correct is the "NOT THIS" one.
Jun 10, 2014 at 7:56 PM
junyoung wrote:
Not exactly the same. For example, in the current design of C# vNext
var x = a?.b.c.d;
is a short-hand for
var x = a?.b?.c?.d;
They are different in Swift, though.

Here's an explanation from lwischik:
return a?.b.c
==>
var t = a?.b; return t.c; // NOT THIS
var t = a?.b; return t?.c; // USE THIS INSTEAD
I think what's more correct is the "NOT THIS" one.
lwischik is describing how you would correctly refactor the code into two expressions in order to attain the same behavior, not how the implementation of the operator works.
var x = a?.b.c.d;
// is equivalent to the following
var x = (a != null ? a.b.c.d : null);

var x = a?.b?.c?.d;
// is equivalent to the following
var x = (a != null ? (a.b != null ? (a.b.c != null ? a.b.c.d : null) : null) : null);
In C#, the statement var x = a?.b.c.d will throw a NullReferenceException if either b or c were to be null, so it can't possibly translate to var x = a?.b?.c?.d; which would not throw an exception.
Jun 10, 2014 at 8:08 PM
Edited Jun 10, 2014 at 8:08 PM
Halo_Four wrote:
That sounds exactly like how the current proposal in Roslyn would work. It does evaluate member access left-to-right, but as soon as the operator applies to a null value it short circuits and immediately returns null.
Under the planned rules, would it be legal to use a?.b in cases where a and b are the same non-classed-constrained generic? What if b is a non-class-constrained generic which is unrelated to a? What is the behavior of a?.b in such cases? Restricting the construct to class-constrained generics seems icky, but silently substituting default(T) seems just as bad. Since nobody seemed to like my idea of allowing the null-case value to be explicitly specified, was the decision made to go with one of the aforementioned approaches, or was some better approach identified [e.g. perhaps allowing non-class constrained generics only in cases where it would be impossible for the left-hand operatand to be null if the member type was not nullable?]
Jun 10, 2014 at 8:53 PM
supercat wrote:
Halo_Four wrote:
That sounds exactly like how the current proposal in Roslyn would work. It does evaluate member access left-to-right, but as soon as the operator applies to a null value it short circuits and immediately returns null.
Under the planned rules, would it be legal to use a?.b in cases where a and b are the same non-classed-constrained generic? What if b is a non-class-constrained generic which is unrelated to a? What is the behavior of a?.b in such cases? Restricting the construct to class-constrained generics seems icky, but silently substituting default(T) seems just as bad. Since nobody seemed to like my idea of allowing the null-case value to be explicitly specified, was the decision made to go with one of the aforementioned approaches, or was some better approach identified [e.g. perhaps allowing non-class constrained generics only in cases where it would be impossible for the left-hand operatand to be null if the member type was not nullable?]
Beats me. If I were to guess I would say that ?. would only be legal in the same cases where the operand can be compared to null, which would exclude non-constrained generic types. Considering that the compiler has to emit identical IL regardless of the case it would have to resort to potential boxing to deal with the comparison. As for the result, I don't think there is an answer as the type would be either a reference type of a Nullable<T> depending on the type of b.

Someone from the C# team would have to weigh in on that one, though.
Jun 10, 2014 at 9:18 PM
Halo_Four wrote:
lwischik is describing how you would correctly refactor the code into two expressions in order to attain the same behavior, not how the implementation of the operator works.
var x = a?.b.c.d;
// is equivalent to the following
var x = (a != null ? a.b.c.d : null);

var x = a?.b?.c?.d;
// is equivalent to the following
var x = (a != null ? (a.b != null ? (a.b.c != null ? a.b.c.d : null) : null) : null);
In C#, the statement var x = a?.b.c.d will throw a NullReferenceException if either b or c were to be null, so it can't possibly translate to var x = a?.b?.c?.d; which would not throw an exception.
Thanks for a good explanation. I read the entire thread from the beginning and have found what I was confused with: short-circuiting has nothing to do with operator associativity.

In the beginning madst wrote:
So advocates of the “left associative” interpretation would put a diagnostic on the code above, warning that this is probably bad, and pushing people to write, instead:
var x = a?.b?.c;
With a null-check again before accessing c.

The other interpretation has been called “right associative”, but that isn’t exactly right (no pun intended): better to call it “short circuiting”.
I think the above explanation is quite misleading since
  • We should still write code like var x = a?.b?.c; to avoid NullReferenceException on accessing b even with the current proposal. It has nothing to do with advocating ?. being left associative.
  • The other interpretation that has been called "right associative" is actually left associative.
Jun 10, 2014 at 10:26 PM
junyoung wrote:
  • We should still write code like var x = a?.b?.c; to avoid NullReferenceException on accessing b even with the current proposal. It has nothing to do with advocating ?. being left associative.
Wrong; it has everything to do with it. We should write a?.b?.c if b can legitimately be null, but we want to be able to specify the cases in which it is not supposed to be null. Therefore, we need the distinction between a?.b?.c and a?.b.c and the “left-associative” semantics does not provide that distinction.
  • The other interpretation that has been called "right associative" is actually left associative.
Also wrong. “Right-associative” doesn’t mean “evaluated from right to left”. All binary operators in C# evaluate their operands from left to right, including right-associative ones such as assignment (=), coalescing (??) and short-circuiting boolean logic (&& and ||).

The reason it has been called “right-associative” is subtle and complex, but it is logically sound. To give a basic simplification, consider an expression such as:
Foo.Bar.Baz
This is semantically equivalent to the hypothetical code
Foo ▷ a => a.Bar ▷ b => b.Baz
where is a hypothetical operator that invokes the lambda on its right-hand side with the argument on its left-hand side. The question immediately arises whether ▷ should be left- or right-associative. In the case of ., it makes no difference; the two are observationally indistinguishable:
Foo ▷ a => (a.Bar ▷ b => b.Baz)
(Foo ▷ a => a.Bar) ▷ b => b.Baz      // same thing
With ?. however it now makes a difference, which is why we’re having this discussion.

By the way, I’m surprised how many people are still arguing about the associativity; that ship has clearly sailed and the consensus reached. Maybe we should move on to something more interesting. I was intrigued by a question raised earlier in this thread but which seems to have gotten lost: What if the return type of the ?. expression is a generic type parameter? For example:
public static T Foo<T>(List<T> list)
{
    return list.?First();
}
Does this compile? If so, what does Foo<int> return if list is null?

My preference would be to extend the CLR so that we can put unconstrained generic type parameters into Nullable<T>. The JIT would translate that to T? when T is a value type and to T when it is a reference type (and translate T.Value into a no-op etc.). However, this requires significant changes to the CLR, which I’m guessing are off the table. In that case, my preference would be to make this a compile-time error, as the only alternatives seems to be to return some other value, e.g. default(int), or to throw an exception at run-time. Both are extremely unlikely to be what the programmer of the above code intended to happen.
Jun 11, 2014 at 4:49 AM
Edited Jun 11, 2014 at 5:22 AM
If you could express extensions methods with a wider range of characters.
static (??)< T0, T1 > ( this  obj : T0? , fn : T0 -> T1 ) : T1
{
  if( obj.HasValue ) return fn( obj.Value );
  return default<T1>();
}
static (??)< T0, T1 >( this obj : T0, fn : T0 -> T1 ) : T1 where T0 is class
{
  if ( obj != null ) return fn( obj );
  return default<T1>();
}
Thinking about as if it was an operator. (with the same precedence as method invocation). Curious of effects if it wasn't
   (??)
   /  \
 (a)  (??)
      /  \
    (b)  (??)
         /  \
       (c)  (d)
Which would be equivalent of .a ?? ( bb ?? ( cc ?? dd ) )
Which I think would allow the type-inference to flow back to the first default<T1>()

But this way has the expense of introducing a lambda function on each .??( ).

Suppose we could express a kind of "pass through extension method" which doesn't involve the lambda.
static (??)< T0 , T1 >( this obj : T0,  then fn : T0 -> T1 ) : T1
notice the then

which could be good for logging / debugging LINQ expressions.
/* PeekAhead returns type Char? */
s.Value == "," && s.PeekAhead(1).??.IsDigit() 
               && s.PeekAhead(2).??.IsDigit()
               && s.PeekAhead(3).??.IsDigit()
Note: These would invoke the extension method in the first example.

Ok that's non-void returning types sort. now for the harder one void types (aka Action<T>)
Should the semantics meaning be if it is null then ignore rest and carry on?
static (??)< T > ( this obj : T? , then act : T -> void ) : void
{
 If ( obj.HasValue ) act( obj.Value )
}
static (??)< T > ( this obj : T , then act : T -> void ) : void where T is class
{
 if ( obj == null ) act( obj )
}

What about a different value to default to?
It could just be expressed as an overload.
static (??) < T0 , T1 >( this obj : T0 , then fn : T0 -> T1, defaultTo : T1 ) : T1 where T0 is class
{
  if ( obj != null ) return fn( obj );
  return defaultTo;
} 
Example
customer.??("-- Unknown Address --").Address.??("-- Unknown City --").City.??("-- unknown state --").State 
Jun 11, 2014 at 5:30 AM
Edited Jun 11, 2014 at 5:30 AM
supercat wrote:
Under the planned rules, ...
The rules we came up with were articulated over a series of different language design meetings, so while the notes are posted to these forums they're scattered. Here I'll draw together my memory of the rules to answer your questions...
would it be legal to use a?.b in cases where a and b are the same non-classed-constrained generic?
You cannot END with something that's a generic and you don't know if it's value-type or reference-type
class C<T> {public T x;}
void f<T>(C<T> y) { var z = y?.x; } // illegal
The reason is that the compiler has to be able to infer the type of "z". If x had been known to be a struct T, then z would have type T? If x had been known to be a class T, then z would have type T. But if we don't know whether T is a struct or a class (i.e. if T is a generic type parameter which lacks struct and class constraints) then we can't pick a type for z.

However, you can ?. off something that's a non-class-constrained-generic...
interface I {public int x;}
void f<T>(T y) where T:I { var z = y?.x; } // allowed
Note that merely writing where T:I doesn't imply that T is a class. It could well be a struct which implements I. That's why this is an example of a non-class-constrained-generic which we ?. off of.

The CLI manages this in the same way that it manages void f<T>(T y) {if (y == null) ...}. In other words, it simply boxes y. For each time the method is JITed with a concrete instantiation of T, it is either a struct or a reference type. If a struct, then boxing it turns it into a boxed struct (which can be compared against null). If a reference type, then boxing is a no-op, and you can still compare it against null.
What if b is a non-class-constrained generic which is unrelated to a? What is the behavior of a?.b in such cases?
Same as above. There's no impact whether b is related to a or not.
Restricting the construct to class-constrained generics seems icky, but silently substituting default(T) seems just as bad.
The construct isn't restricted to class-constrained generics. In the expression a?.b, the a can be anything that makes sense (known to be a reference type, or known to be a nullable value type, or an unconstrained generic). And the b can be anything other than an unconstrained generic (i.e. anything other than a generic where it's not specified whether it's a struct or a class).
Since nobody seemed to like my idea of allowing the null-case value to be explicitly specified, was the decision made to go with one of the aforementioned approaches, or was some better approach identified [e.g. perhaps allowing non-class constrained generics only in cases where it would be impossible for the left-hand operatand to be null if the member type was not nullable?]
A better approach was identified, but I can't parse your final sentence to know whether that was it :(
Jun 11, 2014 at 8:16 AM
Timwi wrote:
junyoung wrote:
  • We should still write code like var x = a?.b?.c; to avoid NullReferenceException on accessing b even with the current proposal. It has nothing to do with advocating ?. being left associative.
Wrong; it has everything to do with it. We should write a?.b?.c if b can legitimately be null, but we want to be able to specify the cases in which it is not supposed to be null. Therefore, we need the distinction between a?.b?.c and a?.b.c and the “left-associative” semantics does not provide that distinction.
  • The other interpretation that has been called "right associative" is actually left associative.
Also wrong. “Right-associative” doesn’t mean “evaluated from right to left”. All binary operators in C# evaluate their operands from left to right, including right-associative ones such as assignment (=), coalescing (??) and short-circuiting boolean logic (&& and ||).
Huh? Isn't the operator associativity all about which hand side of two operators of the same precedence to evaluate first if parentheses are not specified? Even the Microsoft C# documentation says the reverse (emphasis mine):
Except for the assignment operators, all binary operators are left-associative, meaning that operations are performed from left to right. For example, x + y + z is evaluated as (x + y) + z.
The assignment operators and the conditional operator (?:) are right-associative, meaning that operations are performed from right to left. For example, x = y = z is evaluated as x = (y = z).
Here's from Microsoft C++ documentation:
An expression can contain several operators with equal precedence. When several such operators appear at the same level in an expression, evaluation proceeds according to the associativity of the operator, either from right to left or from left to right.
Maybe your "associativity" is different from the one in textbooks.
The reason it has been called “right-associative” is subtle and complex, but it is logically sound. To give a basic simplification, consider an expression such as:
Foo.Bar.Baz
This is semantically equivalent to the hypothetical code
Foo ▷ a => a.Bar ▷ b => b.Baz
where is a hypothetical operator that invokes the lambda on its right-hand side with the argument on its left-hand side. The question immediately arises whether ▷ should be left- or right-associative. In the case of ., it makes no difference; the two are observationally indistinguishable:
Foo ▷ a => (a.Bar ▷ b => b.Baz)
(Foo ▷ a => a.Bar) ▷ b => b.Baz      // same thing
Following your interpretation, every binary operator in C# can be interpreted as "right associative." For example with +,
Foo + Bar + Baz
is equivalent to
Foo ▷ a => a + Bar ▷ b => b + Baz
and
Foo ▷ a => (a + Bar ▷ b => b + Baz)
(Foo ▷ a => a + Bar) ▷ b => b + Baz // Same thing
Therefore, the + operator is right associative (as well as left associative, of course).
Jun 11, 2014 at 9:56 AM
Edited Jun 11, 2014 at 9:56 AM
Isn't the operator associativity all about which hand side of two operators of the same precedence to evaluate first if parentheses are not specified?
No, it is not. The pieces of documentation you dug up mention the order in which the operations are performed. They do not mention the order of the evaluation of the operands.

All left- and right-associative actually means is whether
a + b + c
should be parsed as
(a + b) + c    // left-associative
a + (b + c)    // right-associative
I think you can easily see that in both cases, a, b and c (the operands) can still be evaluated from left to right, and in C# they are. The documentation you dug up refers only to the order in which the + operations are performed.
Following your interpretation, every binary operator in C# can be interpreted as "right associative."
First of all, I wasn’t interpreting anything and I wasn’t saying that anything can be seen as right-associative that actually isn’t. Secondly, you do not need the thingie I invented to see that + could be implemented as either left- or right-associative and it would make no difference for numeric types. However, in C# + is definitely left-associative, which you can easily see by introducing a custom operator overload. I’m going to use < instead to show that it’s definitely left-associative, but you can use + too:
class X
{
    public static X operator <(X x, int y) { Console.WriteLine("int"); return new X(); }
    public static X operator >(X x, int y) { Console.WriteLine("int"); return new X(); }
    public static X operator <(X x, bool y) { Console.WriteLine("bool"); return new X(); }
    public static X operator >(X x, bool y) { Console.WriteLine("bool"); return new X(); }
}
// ...
var x = new X();
Console.WriteLine(x < 1 < 2);
If < were right-associative, the expression would be parsed as x < (1 < 2), giving X < bool, thus the program would output “bool”. However, it is left-associative, which means it is parsed as (x < 1) < 2, giving (X < int) < int and then X < int, and thus it outputs “int” twice. This is actually what happens.

Now, I’m once again surprised that we’re again back to the fundamentals of what associativity even means. I thought we were going to move on to something interesting. Shame that my suggested topic was already stomped out by lwischik, who said that the decision has been made to make it a compiler error.
Jun 11, 2014 at 5:53 PM
lwischik wrote:
You cannot END with something that's a generic and you don't know if it's value-type or reference-type
It would seem like logically one should be able to end with the same type as one started, from the standpoint that given
interface Q<T> { T blah(); }

T f<T>(T it) where T:Q<T>
{ return it?.blah(); }
If that were evaluated as
{ return (it==null) ? default(T) : it.blah(); }
there would be no possibility of a non-null default(T) being returned.
The reason is that the compiler has to be able to infer the type of "z". If x had been known to be a struct T, then z would have type T? If x had been known to be a class T, then z would have type T. But if we don't know whether T is a struct or a class (i.e. if T is a generic type parameter which lacks struct and class constraints) then we can't pick a type for z.
An alternative would be to say that if the member type is TMember, the expression will always yield type TMember, and if the left side evaluates to null the expression should yield default(TMember). That could be "surprising" in some cases, though in the situation where the left and right sides were of the same type surprising situations could never occur.
In other words, it simply boxes y.
That's long been one of my peeves with the way nullable types were handled. IMHO, when generics are added there should have been an explicit "is null" method which would indicate whether its argument was either a null reference, or a nullable whose HasValue was false. I find it absurd that a structure type should need to be boxed when its value is of no interest whatsoever. In release builds the JITter seems to figure out that boxing is silly if a type isn't nullable, but still performs a useless boxing operation when given a non-null Nullable<T>. I've tried writing such a method which uses reflection to create a delegate the first time it's given a particular type, and calls a delegate every time thereafter; when given a non-null Nullable<T> it substantially outperforms ==null; when given a non-nullable value type it substantially outperforms ==null for debug builds only.

With regard to ?., the only time I can see that it could legally be used on a generic that could be a Nullable<T> would be when invoking ToString() (or if ?. yields default(T) for null values, GetHashCode()). In the case of ToString(), invocation on a Nullable<T> whose HasValue is false yields a non-null empty string, rather than a null reference. If the member being invoked is anything other than ToString(), the null check should be skipped for anything that isn't a reference type, though I don't know if there's any way to code that in the CIL.
A better approach was identified, but I can't parse your final sentence to know whether that was it :(
My approach would be to say that a?.b?.c() : d would be equivalent to (var t1=a; ( (t1!=null) ? (var t2=b; (t2!=null) ? t2.c() : d ) : d) [if an expression contained multiple directly-chained ?. operators without intervening parentheses, all would use the same "alternate-value" term]. Expression d would have to be of the same type as member c(), but the type could be an unconstrained generic (e.g. one could write:
T f<T>(Q<T> it. T defaultValue)
{ return it?.blah() : defaultValue; }
Since the compiler wouldn't need to assign null to something of type T, it wouldn't need to know nor care whether null was a valid value for that type.
Jun 11, 2014 at 5:57 PM
Timwi wrote:
Now, I’m once again surprised that we’re again back to the fundamentals of what associativity even means. I thought we were going to move on to something interesting. Shame that my suggested topic was already stomped out by lwischik, who said that the decision has been made to make it a compiler error.
I think the confusion stems from the fact that the term "associativity" is attached to a token which isn't even an operator in the normal sense, since the right-hand side isn't a value.
Jun 11, 2014 at 6:26 PM
Edited Jun 11, 2014 at 6:27 PM
Well, that’s why I invented the hypothetical operator which does have a value (namely, a lambda expression) on its right-hand side and is otherwise semantically equivalent to .. It seems nobody really got it.
Jun 11, 2014 at 7:30 PM
supercat wrote:
I think the confusion stems from the fact that the term "associativity" is attached to a token which isn't even an operator in the normal sense, since the right-hand side isn't a value.
It shouldn't cause confusion. Associativity is a general parsing concept.

And moreover, the normal sense of "operator" includes the member-access operator. That's how mathematicians use the term "operator". It's how the C# language spec uses the term "operator" (see e.g. $1.4 which has a list of all operators, including member access, and $7.2 which calls member-access an "operation", and $18.5.2 which calls it the "member access operator").

There's a narrower sense of the term that .NET developers often use where they refer only to the operators that can be user-defined. I'd rather we avoid this sense of the term when talking about language specification.
Jun 11, 2014 at 7:42 PM
Edited Jun 11, 2014 at 7:43 PM
supercat wrote:
If that were evaluated as
{ return (it==null) ? default(T) : it.blah(); }
there would be no possibility of a non-null default(T) being returned.
Gosh, I wouldn't like it at all if ?. had the possibility of returning something that wasn't null. We have this problem already in VB, where the "Nothing" literal means default(T), and it causes no end of grief... e.g. var x = false ? 1 : Nothing will give you back an integer with value 0, rather than a Nullable<int> with value null like everyone expects.

What you say would make sense if the intent of a?.b is to return Nothing when the null-check on 'a' fails. It wouldn't work if the intent of ?. is to return null when the null-check on 'a' fails.
In release builds the JITter seems to figure out that boxing is silly if a type isn't nullable, but still performs a useless boxing operation when given a non-null Nullable<T>.
Interesting. I'd always trusted the JITter to do the right thing. Have you tried ProjectN? Does its "more-optimized" compilation avoid the useless boxing operation when given a non-null Nullable<T> ?
My approach would be to say that a?.b?.c() : d would be equivalent to (var t1=a; ( (t1!=null) ? (var t2=b; (t2!=null) ? t2.c() : d ) : d) [if an expression contained multiple directly-chained ?. operators without intervening parentheses, all would use the same "alternate-value" term]. Expression d would have to be of the same type as member c(), but the type could be an unconstrained generic (e.g. one could write:
It seems a matter of swings and roundabouts. The way we're currently thinking where it always returns null on a failed check, you can often achieve the same effect by using the ?? operator e.g. a?.b?.c ?? d, except for cases like you showed where the ?. series ends in a call to a non-void function call. The way you propose where it returns Nothing on a failed check, you can't reuse ?? and have to come up with your : operator.

I think it's positively bad to use Nothing, and positively good to re-use the existing ?? operator, and the cases where : works over ?? aren't worth the complexity of adding it.
Jun 11, 2014 at 10:35 PM
ljw1004 wrote:
And moreover, the normal sense of "operator" includes the member-access operator. That's how mathematicians use the term "operator". It's how the C# language spec uses the term "operator" (see e.g. $1.4 which has a list of all operators, including member access, and $7.2 which calls member-access an "operation", and $18.5.2 which calls it the "member access operator").
I wasn't thinking in terms of user-defined operators, but rather thinking of an operator as something which takes one or two expressions, acts upon them, and yields a value. Whether . by itself would counts as an operator under such a definition would depend upon whether one regards a member name as a "value". Semantically, if class Fred has an int field foo, and a method double bar(int x, int y), then .foo would behave like a unary postifx operator which converts a Fred into an integer byref; .bar(int x, int y) would behave as a ternary operator which [in conjunction with the parentheses and comma] turns a Fred and two integers into a double. If it were legal to say foo.(modeFlag ? bar : boz) as an alternative to modeFlag ? foo.bar : foo.boz, or even if one could say foo.(bar), then I might be inclined to regard . as an operator, but I can't think of anything else offhand that would be called a binary operator which must be followed by an identifier whose meaning cannot be resolved at all without knowing the type of the left-hand operand, or where the right side could not be enclosed in parentheses. Some unary operators like typeof don't operate on normal "values", but their operands can be resolved in isolation, unlike the thing to the right of ..
Jun 11, 2014 at 11:25 PM
ljw1004 wrote:
Gosh, I wouldn't like it at all if ?. had the possibility of returning something that wasn't null. We have this problem already in VB, where the "Nothing" literal means default(T), and it causes no end of grief... e.g. var x = false ? 1 : Nothing will give you back an integer with value 0, rather than a Nullable<int> with value null like everyone expects.

What you say would make sense if the intent of a?.b is to return Nothing when the null-check on 'a' fails. It wouldn't work if the intent of ?. is to return null when the null-check on 'a' fails.
In the particular code I showed, where the type of the left-hand operand was the same as the type yielded by the right-hand member, the only way in which the left-hand side could be null would be if default(T) was also null. When T is a struct, default(T) would not be null, but would never be evaluated. I did not mean to imply that I would favor allowing ?. substitute actually use any value of default(T) that wasn't null.
In release builds the JITter seems to figure out that boxing is silly if a type isn't nullable, but still performs a useless boxing operation when given a non-null Nullable<T>.
Interesting. I'd always trusted the JITter to do the right thing. Have you tried ProjectN? Does its "more-optimized" compilation avoid the useless boxing operation when given a non-null Nullable<T> ?
Haven't tried it. Might be interesting. Note that the slow case only arises when a Nullable<someType> is used as a generic parameter so the compiler can't tell that the thing being compared to null is a Nullable<T>. I suspect the JITter doesn't try too hard to optimize the performance of nullable types since code which is actually interested in performance won't use them.
My approach would be to say that a?.b?.c() : d would be equivalent to (var t1=a; ( (t1!=null) ? (var t2=b; (t2!=null) ? t2.c() : d ) : d) [if an expression contained multiple directly-chained ?. operators without intervening parentheses, all would use the same "alternate-value" term]. Expression d would have to be of the same type as member c(), but the type could be an unconstrained generic (e.g. one could write:
It seems a matter of swings and roundabouts. The way we're currently thinking where it always returns null on a failed check, you can often achieve the same effect by using the ?? operator e.g. a?.b?.c ?? d, except for cases like you showed where the ?. series ends in a call to a non-void function call. The way you propose where it returns Nothing on a failed check, you can't reuse ?? and have to come up with your : operator.
As I would like to see it, the operator would never return anything other than either null, or else a specified default value. With the ?. : as I've proposed, code which wanted to compute the hashcode of an object containing a possibly-null field could use someField?.GetHashCode() : 0; If it was desired to have null values map to something other than zero, no problem: someField?.GetHashCode() : 42. Such an approach would eliminate the need to use an implicit default(T) at all. Indeed, if code were required to specify the default value even when using reference types, it would be abundantly clear that a?.b : null could return null even if no instance of a had a null b value.

There are a lot of cases where it is compute expressions of the form a != null ? a.b : someDefault. If a.b is a class type, but will in fact never be null when a is non-null, the expression would (if repeated evaluations were replaced with temporaries) be equivalent to a != null ? (a.b != null ? a.b : someDefault) : someDefault), but I would expect that in the vast majority of cases where the second expression would work, the first would actually be more appropriate (if a.b does yield null for some reason, code shouldn't mask the problem by returning someDefault; if it never yields null, any time spent checking is wasted). Specifying the default value would also eliminate the requirement that the right-hand operator specify a class constraint.
Jun 12, 2014 at 2:22 PM
ljw1004 wrote:
Gosh, I wouldn't like it at all if ?. had the possibility of returning something that wasn't null. We have this problem already in VB, where the "Nothing" literal means default(T), and it causes no end of grief... e.g. var x = false ? 1 : Nothing will give you back an integer with value 0, rather than a Nullable<int> with value null like everyone expects.
That's a bit presumptuous. It tends to be only those coming from C-style languages.

Nothing doesn't strictly have a type. It's type is inferred from usage.
You also need to remember that dominant type comes into play when inference is used.
1 is parsed to have a "real" type of integer, so becomes the dominant type. So what type is Nothing ?
What it the current dominant type? Integer so I'll default to 0.


To return a Nullable<Int> that has no value. You would need to cast the 1 to Nullable<Int>
Dim x0 = If( cond, New Nullable(Of Integer)(1), Nothing)
Dim r0 = x0.HasValue
Dim x1 = If( cond, 1 , New Nullable(of integer)() )
Dim r1 = x1.HasValue
Dim x2 = If( cond, CInt?(1), Nothing ) ' <-- Not yet valid
Dim r2 = x2.HasValue
Jun 12, 2014 at 4:19 PM
AdamSpeight2008 wrote:
ljw1004 wrote:
Gosh, I wouldn't like it at all if ?. had the possibility of returning something that wasn't null. We have this problem already in VB, where the "Nothing" literal means default(T), and it causes no end of grief... e.g. var x = false ? 1 : Nothing will give you back an integer with value 0, rather than a Nullable<int> with value null like everyone expects.
I don't like the idea of having a ?. whose right-hand operator is a value type T yield a Nullable<T>, since that would mean that the semantics of the operator would vary with the type of the right-hand side, and since the only probable usage case would be to use something like ?? to extract the value; perhaps the code generated from a?.GetHashCode() ?? 42 could be executed as (a != null) ? a.GetHashCode() : 42 rather than (var temp = ((a!= null) ? a.GetHashCode : (int?)null), temp != null ? temp.Value : 42) but it seems that if what one wants is to return either the hash code or 42, it would be cleaner to have a syntax that says that [e.g. a?.GetHashCode : 42], without involving nullable types.
Jun 12, 2014 at 6:03 PM
Edited Jun 12, 2014 at 6:36 PM
But the right hand side can't be a different type to the left. If Left and Right are different type but share a common base then the result is the greatest common base type.

Look at the type signature of an IF expression
static IF<T> ( cond : bool , onTrue : Expr<T> , onFalse : Expr<T> ) : Expr<T>
Note Expr<T> is a expression that evaluates to a T

If you replace the T's with Int32 (the type for integer literals)
static IF<Int32>( cond : bool , onTrue : Expr<Int32> , onFalse : Expr<Int32> ) : Expr<Int32>
You can see why Nothing has to be an int32 with Value of 0

@supercat have a look at my proposal further up of a "pass-through extension method"
static (??) < T0 , T1 >( this obj : T0  , then fn : T0 -> T1, defaultTo : T1 = default<T1> ) : T1 where T0 is class
static (??) < T0 , T1 >( this obj : T0? , then fn : T0 -> T1, defaultTo : T1 = default<T1> ) : T1 where T0 is struct
Using your example
 obj.??(defaultValue:= 42).GetHashCode() 
If obj is a class and is null then evaluation ends after ??( ) (with value 42) and doesn't evaluate .GetHashCode
if obj is a struct then it always as a value, so .??. doesn't appear as a possible method.
if obj is nullable then then .??. is a viable method.
if it doesn't have a value then the value defaultTo is used as the return value and doesn't execute further methods eg .GetHashCode after it.
if it does have a value then the fn method is called (which will be the following method) eg .GetHashCode.
r = a.??.b.??.c.??.d
       |    |    |
       |    |    +- returnType(Of d)
       |    |
       |    +------ returnType(of d)
       |
       +----------- returnType(of d)

r = a.b.c.d   r has returnType(of d)

r = d( c ( b( a ) ) )
Thus semantic meaning is preserved.

The following vb.net code (using the roslyn preview) partially solves the issue except for the "pass-through"" semantics.
  <Runtime.CompilerServices.Extension>
  Function __(Of T0 As {Structure}, T1)(obj As T0?, fun As Func(Of T0, T1), Optional def As T1 = Nothing) As T1
    If obj.HasValue Then Return fun(obj.Value)
    Return def
  End Function
  <Runtime.CompilerServices.Extension>
  Function __(Of T0 As {Class}, T1)(obj As T0, fun As Func(Of T0, T1), Optional def As T1 = Nothing) As T1
    If obj IsNot Nothing Then Return fun(obj)
    Return def
  End Function
Jun 12, 2014 at 6:45 PM
AdamSpeight2008 wrote:
@supercat have a look at my proposal further up of a "pass-through extension method"
I'm not sure I fully understand the notation, but I think we're on the same page, the only difference being where the default value should be given. I would favor having the default value be specified earlier in the expression rather than later, but I couldn't figure any good syntax, especially if the same default value should be used for more than one part of the expression.

Also, I think it should be legal for T0 to be an unconstrained generic. It's true that for some types of T0 the default value would never be used, but so what? If one wants to compute the hashcode for an aggregation of generic-type values, and have null be regarded as having some particular value rather than throwing an exception, one should be able to use the same code regardless of whether the generic types could possibly hold nulls.

Also, I don't think overloading rules would presently support it, but I would have the default for defaultValue only be applicable when the result type can support null as a value; I would suggest that if the programmer wants default(T) for other types, the programmer should explicitly state that intention.
Jun 12, 2014 at 7:36 PM
Edited Jun 12, 2014 at 7:45 PM
In my proposal the fun isnot treated as a Lamda but is the following method call. Think it as being treated as a further extension method on .??. (in vb example .__)
Expr<T0,T1> would be a better type than Func<T0,T1>

The overloading rules do support it (at least in the roslyn preview). If you don't include the constraint and the T0 is a struct (let's assume Int32)
then the internal
If obj IsNot 0 has incorrect semantics for the value of zero.
So you require the constraints to differentiate struct, class and nullable<struct>

The defaultValue is optional so if don't in include it you'll get default<T>if theT0` is null (aka default<T>).
(this obj : T0, then fun : Expr<T0,T1> , optional defautValue : T1 = Default<T1> ) : T1
The compiler would build the following semantically.
IF obj IS null Then
  Evaluate  obj.fun 
Else
  Evaulate defaultValue
End If
Example
  <Runtime.CompilerServices.Extension>
  Function LookAhead(text As String, index As Integer, ahead As String) As Char?
    If text Is Nothing Then Return New Char?
    If index < 0 OrElse index >= text.Length Then Return New Char?
    If ahead < 1 Then Return New Char?
    If (index + ahead) >= text.Length Then Return New Char?
    Return New Char?(text(index + ahead))
  End Function

  <Runtime.CompilerServices.Extension>
  Function IsDigit(c As Char) As Boolean
    Return Char.IsDigit(c)
  End Function

  <Runtime.CompilerServices.Extension>
  Function __(Of T0 As {Structure}, T1)(obj As T0?, fun As Func(Of T0, T1), Optional def As T1 = Nothing) As T1
    If obj.HasValue Then Return fun(obj.Value)
    Return def
  End Function
  <Runtime.CompilerServices.Extension>
  Function __(Of T0 As {Class}, T1)(obj As T0, fun As Func(Of T0, T1), Optional def As T1 = Nothing) As T1
    If obj IsNot Nothing Then Return fun(obj)
    Return def
  End Function

  Function Valid(Text As String) As Boolean
    Dim L = Text.Length
    Dim I = 0
    While I < L
      Select Case Text(I)
        Case ","c
          If I = 0 Then Return False
          If Not (Text.LookAhead(I, 1).__(AddressOf IsDigit) AndAlso
                  Text.LookAhead(I, 2).__(AddressOf IsDigit) AndAlso
                  Text.LookAhead(I, 3).__(AddressOf IsDigit)) Then Return False
          I += 4
        Case "0"c To "9"c
          I += 1
        Case Else
          Return False
      End Select
    End While
    Return True
  End Function
Let's rewrite this section using .??.
          If Not (Text.LookAhead(I, 1).__(AddressOf IsDigit) AndAlso
                  Text.LookAhead(I, 2).__(AddressOf IsDigit) AndAlso
                  Text.LookAhead(I, 3).__(AddressOf IsDigit)) Then Return False
rewritten as
If Not (  Text.LookAhead( I, 1).??.IsDigit AndAlso Text.LookAhead( I, 2).??.IsDigit AndAlso Text.??.IsDigit ) Then Return False
Notice how the extension method .IsDigit appears just as a extension method on .??

Let's say instead of .IsDigit it is ,IsNotDigit
Function IsNotDigit( c As Char) As Boolean
  Return Not Char.IsDigit( c )
End Function
Then
If Text.LookAhead(I,1).??.IsNotDigit() OrElse Text.LookAhead(I,2).??.IsNotDigit OrElse Text.LookAhead(I,3).??.IsNotDigit Then Return False
Would produce the incorrect result.
So we need to override the Default<T> value to be True instead.
If Text.LookAhead(I,1).??(True).IsNotDigit() OrElse Text.LookAhead(I,2).??(True).IsNotDigit OrElse Text.LookAhead(I,3).??(True).IsNotDigit Then Return False
example 2
customer.??("-- Unknown Customer --").Address.??("-- Unknown Address --").City.??("-- unknown city --").State.??("-- Unknown State --")
If null happens on    | result
  customer              "-- Unknown Customer --"
  .Address              "-- Unknown Address --"
  .City                 "-- Unknown City --"
  .State                "-- Unknown State --"               
Jun 16, 2014 at 6:59 PM
Your use of extension methods makes me wish for a couple of extension-related features in .NET languages: (1) the ability for a class (or--in vb.net--module) to define private extension methods, whose usage would be restricted to the method in question, rather than requiring that all extension methods must be declared within a static class; (2) a means by which classes could declare extension methods which should be applicable on their own type; (3) if there were a syntactic means of distinguishing such calls from normal ones, a means of having an extension method take the implicit "this" as a byref parameter and have such use limited to mutable storage locations. VB.NET actually allows extension methods to accept the implicit parameter as a byref, but uses the same syntax as ordinary method calls, and does nothing to prevent nonsensical invocation of such methods read-only values (grr...)

Many of the intended purposes of ?. could be handled quite nicely by extension methods, but would be much cleaner if rules of extension method accessibility followed more closely with the other rules of member accessibility, rather than being in their own little world.