views:

920

answers:

14

I often find myself doing:

foo = foo ?? x;

Why can't I do:

foo ??= x;

Edit: I know it's not part of the language... My question is "why not"? I find the necessity to repeat "foo" to be unpleasing and potentially error-prone. It looks just as ugly as:

foo = foo + x;
A: 

The ??= operator is not part of C#.

GWLlosa
I think he knows that. The question is: "Is there a good reason why?"
Joel Coehoorn
Not very helpful...
Dscoduc
A: 

Because there is no such ??= operator in C#.

Whilst += may seem like two operators represented with different syntax its just one operator.

AnthonyWJones
+5  A: 

There is no operator that performs this operation. However, it's an interesting suggestion for a future version of the language. I suspect that it hasn't been included thus far because the primary use-case for the coalescing operator, ??, is with the Nullable type and getting the value as in:

int? testValue;

return testValue ?? 0;

Rather than in assignment operations like your example. Also, whereas += is guaranteed to modify the value of foo in all cases but += 0, ??= would not.

Jeff Yates
I was thinking the same, it would be a nice shorthand.
Chuck Conway
It would, but I think it mixes up semantics considering the primary usage with Nullable types where it is used to provide a default value in the absence of an actual value, rather than during assignment of a value to an otherwise null variable.
Jeff Yates
No such guarantee exists. I could += or -= x where x is 0 and I could *= or /= x where x is 1. ??= is no better or worse than ?? itself in terms of syntactic sugar.
jmucchiello
@joe: I think you missed my point. I stated that in all cases BUT where x is 0. ??= is worse because the value is ONLY modified if the initial value is not null, whereas the modification of the value for += or -= is based on x, not the value receiving assignment.
Jeff Yates
Therefore, it is more likely that += or -= will result in an assignment than ??= would. ?? is a conditional operator rather than an arithmetic one and as such, it just doesn't fit the pattern used by +=. -=, *=, etc.
Jeff Yates
+18  A: 

When I think about it,

foo = foo ?? x

is really just

foo = foo != null ? foo : x

and at that point, the analogy to += starts to fall apart.

Brian Genisio
This was my thought too. I'd be interested in the IL for both statements, I think they're the same. And then ??= doesn't hold up.
Anthony Mastrean
You might be interested in this: http://stackoverflow.com/questions/547249/-operator-vs-if-statement-performance/547333#547333Apparently the IL is not actually quite the same.
mquander
+13  A: 

There's no reason why there couldn't be such an operator, but I suspect the added complexity of the language, though slight, outweights the benefit (which I would deem "very slight").

Basically any addition to the language has a pretty high bar to clear. You say you use this quite often - how often, really? While I deem ?? handy, I can't say I use even that terribly frequently.

Jon Skeet
+1, couldn't remember last time I used the ?? operator (3 usages in 90 KLOC+)
sixlettervariables
+2  A: 

Mainly because +=, -= etc were added pretty much as afterthoughts to maintain compatibility with C & C++.(*) Since ?? is not part of C or C++, there was no need to add the extra operator.

(*) Note that in C++, when defining operators for a class, one normally defines operator+=() and then implements operator+() based on it. (It's generally the most efficient way). However, in C#, one implements operator+, and the compiler automatically adds operator+= based on oper+. This is why I say that the += operators are a tacked on afterthought.

James Curran
Doesn't strike me as a tacked-on afterthought, but rather compiler-enforced consistency.
David Thornley
James Curran
+1  A: 

That style of statement feels like a lazy-load from a property getter. In which case, I would choose this syntax

private Foo myFoo;
public Foo MyFoo
{
    get
    {
        return myFoo ?? (myFoo = new Foo());
    }
}
Anthony Mastrean
but you still have to repeat "foo"
JoelFan
We all repeat "foo" sometimes.
Anthony Mastrean
+3  A: 

I don't see many reasons why you would use the ?? operator to self-assign a variable.

Perhaps you're setting foo based on some database value that happens to be NULL, so it would make more sense to use the ?? operator during that assignment (which eliminates the need for ??=):

foo = (int?)rows["possiblyNullCount"] ?? 0;

as opposed to:

foo = (int?)rows["possiblyNullCount"];
foo = foo ?? 0;
John Rasch
It's nothing to do with a database... I just like using null to mean "no value set yet"
JoelFan
+2  A: 

While not exactly what you are asking for (it's not ??=)... You could perhaps leverage Extension Methods.

static void Main(string[] args)
{
    object foo = null;
    object x = "something";
    Console.WriteLine(foo.NullToValue(x));
}

public static class ObjectExtensions
{
    public static object NullToValue(this object obj, object value)
    {
        return obj != null ? obj : value;
    }
}

I haven't spent an exhaustive amount of time thinking of possible ways this won't work, but it does seem to pass the smell test in my sample application...

Dscoduc
+7  A: 

?? is not an "operator" in the sense that it does an "operation" with the value of the operands. You should view it just as a language construct.

Suppose you had:

node = node.next;

Would you then want to be able to do the following?

node .= next;

I think ??= doesn't exist for the same reason that .= doesn't exist.

Besides, unary operators like +=, *=, etc. have direct counterparts at the assembly level. Pseudo-assembly:

add reg0, 1
mul reg1, 5

It's just "natural" that these operators exist.

Ates Goral
I think you meant "node .= next;" instead of "node .= node;"
Biswanath
@Biswanath: Fixed, thanks!
Ates Goral
What's sacred about the difference between an operator and a language construct? "node .= next;" has at least syntactic parallels, and consistent syntax is always nice. Nor do I particularly care what operators have direct assembler counterparts.
David Thornley
I don't find the assembly analogy meaningful. add reg0,1 is not the same as x+=1. load reg0,st+34;add reg0,1;store st+34,reg0 is closer to += in meaning.
jmucchiello
@David Thornley: It's about polluting the language vocabulary. IMHO, the more there are multiple, unnecessary ways of writing the same thing, the more unnecessarily messy a language becomes. Isn't this one of reasons PHP is despised in some circles?
Ates Goral
@joe_mucchiello: I agree that my assembly analogy is not a strong argument. I was referring more to the possible origins of those unary operators -- it feels "natural" from an assembly perspective. I wasn't suggesting that C code is compiled that way.
Ates Goral
+10  A: 

In general, the C# language design team is conservative about adding new syntax. They say that the value of an addition to the language must be weighed against the cost of increased complexity in the language.

Peter Hallam was the C# Compiler development lead for a while, and also a member of the C# language design team. He wrote about his way of measuring a new feature, called the Yardstick, although he was focused more on interactive GUI features than language features.

This text is particularly relevant to the question of ??=:

Often the right design decision is to not change anything. This is probably the most important lesson I've learned from watching Anders in the C# language design meetings. Often an area of the language is raised in which there apppears to be some real gains which could be made. We could prevent the user from a common coding error, or we could improve the usabilityof the language for a certain problem domain. Then after thinking really hard, through all of the options for addressing the issue, the answer is to do .... nothing! Even though the problem is valid, and it looks like we should be able to add something to improve the situation, after careful reflection there is no way to address the issue which does not cost more than the solution gains. Many of the most important and valuable decisions I've seen Anders make are decisions to not add complexity to the language unless the added value justifies the complexity. In borderline cases, he allmost allways choses nothing over adding something which is marginal.

References:

Jay Bazuzi
+5  A: 

There's a much simpler answer everyone is missing while discussing whether the analogy of ??= to += makes sense.

Question: Why can't you do foo ??= x; in C#?

Answer: Because every feature starts with minus 100 points, features start out nonexistent and somebody has to make them happen and most likely if they added that feature, those resources have been spent on something that would have a greater total benefit to the customer base:

... think of all the time and effort necessary to design how the feature should work, nail all the boundary conditions, then code it up, write automated tests for it, ... write up the documentation and help text, and continue maintaining the code, tests, and documentation for the feature's anticipated lifetime (which in this case is probably forever). Could all those resources have been spent on something that would have a greater total benefit to the customer base? (The answer to that is always "Yes"—everybody and her sister-in-law can find a way to finish the sentence, "I can't believe they wasted all that time on this stupid feature instead of fixing...")

Grant Wagner
+1  A: 

I miss it too - Ruby has ruined me. Here is a similar construct that you can use in an expression (if you aren't allergic to side-effects):

foo ?? foo = x;

as in:

return foo ?? foo = x;

or (for illustration only!):

DoStuff( foo ?? foo = x );

Using this pattern outside of a property getter is probably not a great idea.

Gabe Moothart
+3  A: 

I think the biggest reason would be as a good programming practice you should avoid assigning a variable to itself unnecessarily.

x = x;

Seems useless doesn't it? Instead of foo = foo ?? x; you should be doing

if(foo==null)
{
  foo = x;
}

Not only this describes your intent better, it also avoids redundant writes to possibly a memory location, improving CPU cache utilization and register optimizations.

If it's not the performance but less typing that you're interested in, create a function:

static void SetIfNull(ref object variable, object value)
{
  if(variable == null)
  {
    variable = value;
  }
}    
SetIfNull(ref foo, x);

JIT actually might be able to inline this, making your code as fast as a theoretical foo ??= x; I actually verified that JIT inlines such calls:

mov         rax,qword ptr [rsi] 
test        rax,rax 
jne         0000000000000093 
mov         qword ptr [rsi],rdi

However this still may not be a good programming practice as another programmer can assume the passed expression will not be executed if the variable is not null. Such as:

SetIfNull(ref foo, new List<x>());

In this case you introduce the overhead of creating object unnecessary. That's why I think my first solution

if(foo==null) foo = x;

fits to this purpose much better as it avoids second expression completely and has all small performance benefits.

ssg