Proposal
I'd like to propose an idea for next C#, with name: null-coalescing assignment operator
We can combine the ?? and = operators (??=) like, += and -= ...
Sample:
myObject.MyStringList ??= new List<string>();
Assign if the left is null...
In C# 6 we had:
myObject.MyStringList = myObject.MyStringList ?? new List<string>();
Another sample:
(myObject.MyStringList ??= new List<string>()).Add("something");
This is very simple, but useful...
Thanks
Dupe of #205, #3366, #5163, #10249, #10556, #11394 and #12606.
Per @gafter:
The benefits of this proposal do not overcome the drawbacks in terms of language complexity. It is unlikely to ever have a high enough benefit-for-cost to make us prefer it over many other things we could do in this release or many releases into the future.
However, as mentioned at https://github.com/dotnet/roslyn/issues/205#issuecomment-215420655 there seems to be a decent amount of recurring interest in such an operator so there is a community prototype.
@HaloFour makes me eat my words.
This would probably make more sense along with #1276, so that ?.
produces an lvalue.
x?.P = y;
if (x != null) x.P = y;
x?.P ??= y;
if (x != null) if (x.P == null) x.P = y;
@alrz I find ??=
rather clear in its meaning while ?.
lvalues look very confusing.
@orthoxerox they wouldn't be the same thing though the use cases are kinda similar.
I understand that, but the effect of x?.P?.Q = y;
is not immediately obvious, it feels an annoying shorthand like while (*dst++=*src++);
. Maybe I will change my mind when it becomes as idiomatic as the latter example.
@alrz
I'd be concerned about the subtleties of how that would be implemented. For example:
// is the method called even if x is null and the result simply discarded?
x?.P = SomeComplexCalculation();
// are there any assignments if x or y are null?
x?.P = y?.P = z;
Although I guess you could argue that assignment to a property isn't really any different from invoking a method:
x?.P = y;
// same as:
x?.SetP(y);
// same as:
if (x != null) { x.SetP(y); }
@HaloFour Beyond the simple case p ?= F()
which can be translated to p ?? (p = F())
in an expression context, those concerns are also associated with the ?=
operator.
x ?= y ?= F(); // as a statement
var r = x ?= y ?= F(); // as an expression
How these should be translated? I do prefer lazy evaluation of the right-hand-side, but it would be weird if y
doesn't get initialized if x
wasn't null
!
PS: I like ?=
operator better as we have |=
which behaves like an =
and ||
for booleans.
This promotes usage of mutability and null
.
@dsaf,
You summarised my dislike of this proposal far more succinctly than I was going to. :smile:
This promotes usage of mutability and null.
I disagree. You can't remove them either and some operations essentially need null and/or mutability, e.g. lazy initialization or caching. And since C# is not a pure functional language these patterns are pretty common (because you don't have the m-word to handle state). I'd argue that there should be some mechanism to _manage_ mutability and null instead of discouraging them, namely, #5032 and #7626.
some operations essentially need null and mutability, e.g. lazy initialization
It _is_ actually possible to have your proverbial cake and eat it too, by utilizing Lazy<T>
. The people over at Microsoft have already worked hard on making that class mutable once _and_ thread-safe, so you don't have to.
Yes, it's a little more typing if you want to use it everywhere right now. Yes, there have been suggestions to add eg. a lazy
keyword for auto-properties to make the compiler emit a Lazy<T>
backing field (and @alrz himself even suggests this could be covered by Replace/Original+a marker Attribute, though his example uses ??
instead, which may or may not be thread-safe).
By "lazy initialization" I meant any initialization that occurs after construction (you don't always have access to the context from which the value is initialized), but sure, you could do it with a simple null check. More to the point, this operator is just a syntactical sugar which targets readability and conciseness. Anyways, I think the two proposals (#13737 and #1276) are complimentary and are more helpful together.
I strongly dislike Lazy<T>
and never want to see it integrated as the only option for a lazy
keyword.
It's definitely not for every situation. If your class is single-threaded by design, as all are unless you're doing something special, ??=
is optimal.
See https://twitter.com/nick_craver/status/722040083944235008 too. 馃槅
This is now being tracked at https://github.com/dotnet/csharplang/issues/34
Most helpful comment
@HaloFour makes me eat my words.