Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Proposal] Null-coalescing Assignment Operator: ??= #205

Closed
judemelancon opened this issue Feb 2, 2015 · 17 comments
Closed

[Proposal] Null-coalescing Assignment Operator: ??= #205

judemelancon opened this issue Feb 2, 2015 · 17 comments
Labels
Area-Language Design Feature Request Language-C# Resolution-Won't Fix A real bug, but Triage feels that the issue is not impactful enough to spend time on.

Comments

@judemelancon
Copy link

??= would have semantics analogous to the existing compound assignment operators like +=, %=, and <<=. More precisely, x ??= y would be equivalent to x = x ?? y except that x is evaluated only once. It would have clear, if not vast, utility. Hopefully, it would not be an unreasonably large effort.

It is perhaps debatable whether

object o = GetFirstChoice( foo, bar, someLongArgument )
         ?? GetSecondChoice( foo, bar, someLongArgument )
         ?? GetFallback();

looks better than

object o = GetFirstChoice( foo, bar, someLongArgument );
o ??= GetSecondChoice( foo, bar, someLongArgument );
o ??= GetFallback();

However, the latter seems easier to step through in the debugger.

Furthermore, a use case like

private static void ApplyNewSettings( SettingsSource newSource ) {
    // Set each setting if and only if it is not already set to a non-null value.
    // This could be e.g. applying defaults after deserializing user settings.
    this.SomeSetting ??= newSource.SomeSetting;
    // ...
}

is less repetitive with ??=.

@mirhagk
Copy link

mirhagk commented Feb 3, 2015

I agree the stepping through the debugger would be nice, but I don't think it would be clear whether o ??= GetFallback(); expands to:

o = o ?? GetFallback();

of

o = GetFalback() ?? o;

From your initial example it looks to be option 1, but the final use case would only work with option 2 (the semantics of ApplyNewSettings with option 1 would be to provide defaults if it's not already assigned, it would not do anything if the settings are already defined)

@judemelancon
Copy link
Author

@mirhagk I meant option 1 in both cases. ApplyNewSettings() was meant to only set settings that were not already set (as opposed to set only settings present in the new settings). I added a clarifying comment. I apologize for the ambiguity.

@ashmind
Copy link
Contributor

ashmind commented Feb 3, 2015

I think it is a great idea. It might be worth to add a separate proposal for &&= and ||= as well.

@MgSam
Copy link

MgSam commented Feb 4, 2015

I've always wanted this operator as well. When assigning default values for a variable that has already been declared (or a parameter passed in) this could save a lot of boilerplate and condense two lines of code into one succinct statement.

if(someLongAndAnnoyingToTypeVariableName == null) 
    someLongAndAnnoyingToTypeVariableName = new Foo();

vs.

someLongAndAnnoyingToTypeVariableName ??= new Foo();

@mburbea
Copy link

mburbea commented Feb 4, 2015

@ashmind , I don't see a point in &&= or ||= they are equivalent to &= and |= but they will not short circuit if the value is false or true respectively.

a &= SomeValue()
a &&=SomeValue()

@ashmind
Copy link
Contributor

ashmind commented Feb 4, 2015

@mburbea I'll create a separate item for those when I get a chance, to avoid confusing ??= discussion.

@paulomorgado
Copy link

I think this would be a great semantic improvement. It's obvious that the left is being assigned only if it's null.

But the first exemple, at most, just needs a few parenthesis to work now.

@gafter
Copy link
Member

gafter commented Sep 13, 2015

It seems unlikely we'd ever do this.

@gafter gafter added the Resolution-Won't Fix A real bug, but Triage feels that the issue is not impactful enough to spend time on. label Sep 13, 2015
@ashmind
Copy link
Contributor

ashmind commented Sep 24, 2015

@gafter Can you please elaborate?
Is it a question of effort, or is it rejected from the language design?

If it's the design, then it would be very useful good to discuss why, to avoid spending time on similar proposals (e.g. ||=).

If it's the effort, then can't it be "Up For Grabs" instead of "Won't Fix"?

@gafter
Copy link
Member

gafter commented Sep 24, 2015

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.

@ashmind
Copy link
Contributor

ashmind commented Apr 28, 2016

Given the amount of interest in it (5 linked items) I've decided to try making a prototype -- which is currently at https://github.com/ashmind/roslyn/tree/features/coalesce-assignment. That's my first attempt at a Roslyn thing, so I'm sure I'm doing everything wrong.

I've also added that branch to TryRoslyn:
http://tryroslyn.azurewebsites.net/#b:ashmind-features-coalesce-assignment/K4Zwlgdg5gBAygTxAFwKYFsDcAoADsAIwBswBjGUogQxBBgGEYBvbGNmFAJ0lgA8d2HZN2gwEA9q3b5iZGADcA9mAAmMALIAKAJTMpgtrxgBeGACJeZiQZgB6WzAAWyZLhAAue1DDJHhAHSkiui2KorIEKjItpyKIEQIELZgtMCoILYATAAMAKz6BggwAPzFpvwFAL7YlUA=

@ashmind
Copy link
Contributor

ashmind commented Apr 28, 2016

One open question from the prototype:
If we have x ??= y, and x is not null, should the assignment x = x still happen?
The presence of that assignment would be observable if e.g. you have logic in property setter.
My feeling is it shouldn't, but would be good to know if I'm missing any edge cases.

I expect the answer to apply to any future implementations of &&= and ||= as well.

@alrz
Copy link
Member

alrz commented Apr 28, 2016

@ashmind Should this work for a conditional access? x?.y ??= z; Related: #1276 -- "the ?. Operator never produces an lvalue"

btw, tryroslyn is amazing!

@MgSam
Copy link

MgSam commented Apr 28, 2016

@ashmind I think it should not perform the assignment if x is not null. The ?? operator is currently short circuiting.

http://csharppad.com/gist/680db2bb9216f2909ddb226f10a91c18

Nice work!

@judemelancon
Copy link
Author

@ashmind I am pleased to see your prototype and delighted by its quality. The diff looks pretty clean and direct. The comments raise a couple good questions about the details of the correct behavior, particularly regarding type inference.

I agree that when x is not null the assignment shouldn't happen, unless I am also missing some good reason.

@ashmind
Copy link
Contributor

ashmind commented Apr 30, 2016

@alrz
Thanks!

Should this work for a conditional access?
I think this must be consistent with standard assignment. If #1276 is ever implemented for properties then yes -- but only then.

@MgSam @judemelancon
Thanks for your feedback!
I think you are right -- there is no reason to perform assignment to the same value. That would mean I can't just naively lower to ??, but I'll find a way to do some reuse.

@judemelancon
Copy link
Author

dotnet/csharplang#34 is this feature.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area-Language Design Feature Request Language-C# Resolution-Won't Fix A real bug, but Triage feels that the issue is not impactful enough to spend time on.
Projects
None yet
Development

No branches or pull requests

8 participants