Proposal: inverted null-coalesce operator ?! #4424
Replies: 38 comments 3 replies
-
I personally think, that it is a wonderful idea, I do however dislike the token I would like to see the pipe-operator |
Beta Was this translation helpful? Give feedback.
-
Ah, never thought of that scenario, nice! What token to use is of no big importance to me though. You may be able to flip it around to My initial thought of I like How about |
Beta Was this translation helpful? Give feedback.
-
Using existing features: string possibleIntInput = ...
int? possibleIntValue = possibleIntInput?.ParseInt32();
static int? ParseInt32(this string str) { ... } |
Beta Was this translation helpful? Give feedback.
-
Or with a generic helper function: static TResult Do<TInput, TResult>(this TInput input, Func<TInput, TResult> func)
{
return func(input);
}
string possibleIntInput = ...
int? possibleIntValue = possibleIntInput?.Do(int.Parse); |
Beta Was this translation helpful? Give feedback.
-
Yes, it is possible to "overcome" this using extension methods. However, I don't find extension methods as expressive, and, if I were to start passing delegates around I'd have to check them for null too. It's not ideal! |
Beta Was this translation helpful? Give feedback.
-
Just a crazy idea but what do you think about the following syntax:
|
Beta Was this translation helpful? Give feedback.
-
I'm all for it as long as it works with the rest of C#! (: |
Beta Was this translation helpful? Give feedback.
-
Yeah it's a bit tricky. 😄 |
Beta Was this translation helpful? Give feedback.
-
int? possibleIntValue =
from x in possibleIntInput
select int.Parse(x); The only problem is, this doesn't work because nullable value and reference types don't mix until/unless we get nullable reference types in C# vNext. |
Beta Was this translation helpful? Give feedback.
-
Also, |
Beta Was this translation helpful? Give feedback.
-
@niklaskallander Yes, but is |
Beta Was this translation helpful? Give feedback.
-
@orthoxerox Again, am I missing something? |
Beta Was this translation helpful? Give feedback.
-
@niklaskallander it's possible to implement |
Beta Was this translation helpful? Give feedback.
-
You can do nearly the same with an extension method: using System;
static class Extensions
{
public static TResult Apply<T1, TResult>(this T1 x, Func<T1, TResult> f) => f(x);
}
class Program
{
static int? F(string s) => s?.Apply(int.Parse);
} |
Beta Was this translation helpful? Give feedback.
-
@ufcpp Using extension methods has already been proposed by @qrli a few comments ago, and as I replied to his proposal: Extension methods are not as expressive and passing delegates gives you more stuff to null-check. It's not ideal! @orthoxerox Now I follow, thanks for explaining! Unfortunately, as with all other proposals using extension methods (which this also is but with some sugar on top), it's not as expressive and the linq syntax is too verbose for my liking. |
Beta Was this translation helpful? Give feedback.
-
@niklaskallander Proposed new language features should be discussed at the C# repo so you may want to close this and open a new issue there. |
Beta Was this translation helpful? Give feedback.
-
If we're going for syntactic sugar then piping would surely be ideal because the reverse-coalescing would still require you to provide the input twice |
Beta Was this translation helpful? Give feedback.
-
I often have the pattern of with this i could change it to so it'd be cool if the left hand side could treat false as nully (or null as falsey) |
Beta Was this translation helpful? Give feedback.
-
I need this feature. But my proposition about alias is This means: when vendorId is Null then assign Null to car.vendor, otherwise get vendor by that vendorId. You can also write the same using |
Beta Was this translation helpful? Give feedback.
-
|
Beta Was this translation helpful? Give feedback.
-
and what does it do? My VS does not recognize it |
Beta Was this translation helpful? Give feedback.
-
|
Beta Was this translation helpful? Give feedback.
-
This is possible in JavaScript using the console.log(null && "Foo") // null
console.log({} && "Bar") // Bar I would say |
Beta Was this translation helpful? Give feedback.
-
Bumping this up. Here is one use case example (presuming !? is new operator): return FirstName + (MiddleName !? $" {MiddleName}") + ' ' + LastName; |
Beta Was this translation helpful? Give feedback.
-
Isnt effectively the same there? |
Beta Was this translation helpful? Give feedback.
-
@drdamour - Try it. You may notice there's an extra space when there's no middle name. |
Beta Was this translation helpful? Give feedback.
-
This is getting a little of topic. But, no, that's not the same because of the space @iricigor wants to insert a space before MiddleName if it isn't null. His example isn't the best example because there a thousand other ways to solve that problem, but that's not the point. PS. Here's one way: |
Beta Was this translation helpful? Give feedback.
-
Ah yeah, missed the space. Nice example |
Beta Was this translation helpful? Give feedback.
-
Although there have been mentions of extension methods here, and it was said that this proposal is focused on a language feature, I would like to add another workaround. What we use extensively in our code base is a set of extension methods that is specifically made for checking the nullable for null and applying a transformation function on non-null values. This works because extension methods can also be called for a string possibleIntInput = ...
int? possibleIntValue = possibleIntInput.GetOrNull(int.Parse); The solution is far from perfect, however, due to the need for all combinations of receiver and transformed type struct/class constraints. Also, not all methods can share the name public static TResult GetOrNull<TValue, TResult>(this TValue value, [InstantHandle] Func<TValue, TResult> get)
where TValue : class
where TResult : class {
if (value == null) {
return null;
} else {
return get(value);
}
}
public static TResult? GetValueOrNull<TValue, TResult>(this TValue? value, [InstantHandle] Func<TValue, TResult> get)
where TValue : struct
where TResult : struct {
if (value == null) {
return null;
} else {
return get(value.Value);
}
} (other combinations omitted for brevity) |
Beta Was this translation helpful? Give feedback.
-
It appears that the workaround suggestions depend on only the original evaluated object getting passed. I believe this condition would break them:
Instead of:
In this case we only want newObjects if oldObjects is not null. Because MakeNewObjects returns a collection of newObjectType, if oldObjects is null then newObjects would be a null List of newObjectType. |
Beta Was this translation helpful? Give feedback.
-
I'd very much like to see a new operator in C# that kind of does the opposite of the null-coalesce operator
??
(like the null propagation operator?
but still different).Usage example:
If
possibleIntInput
isnull
, thennull
is returned otherwise an attempt is made to parse it (or whatever other thing you'd want to happen as long as the left-hand object/value is notnull
).Then you could avoid less expressive code like:
dotnet/roslyn#5445 proposes forward piping with null propagation behavior, and I would love being able to write something like this (it's so expressive and functional-like):
but I don't just want forward piping, I also want a syntax for either
null
or{whatever code}
(that returns an object/value of whatever type is expected by the context).What do you think?
Beta Was this translation helpful? Give feedback.
All reactions