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:
string possibleIntInput = ...
int? possibleIntValue = possibleIntInput ?! int.Parse(possibleIntInput);
If possibleIntInput
is null
, then null
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 not null
).
Then you could avoid less expressive code like:
string possibleIntInput = ...
int? possibleIntValue = possibleIntInput != null
? int.Parse(possibleIntInput)
: null;
https://github.com/dotnet/roslyn/issues/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):
string possibleIntInput = ...
int? possibleIntValue = possibleIntInput ?> int.Parse;
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?
I personally think, that it is a wonderful idea, I do however dislike the token ?!
, as it is not intuitive (IMO) and could possibly create some confusion with a ternary operator followed by a logical not: a ? !b : c
=/= a ?! b : c
.
I would like to see the pipe-operator |>
and its null-coalescent partner ?>
implemented, as I love functional programming and personally think, that C# could be more powerful in this direction.
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 !?
instead but I'm not convinced you'd find that more intuitive.
My initial thought of ?!
was to build on the null propagation syntax but somehow indicate a "hand-over" (or whatever one would want to call it) instead of a continued use of the null-checked object (as in the case of null propagation).
I like ?>
but I think that token fits better for a forward piping scenario.
How about ?:
?
Using existing features:
``` c#
string possibleIntInput = ...
int? possibleIntValue = possibleIntInput?.ParseInt32();
static int? ParseInt32(this string str) { ... }
```
Or with a generic helper function:
c#
static TResult Do<TInput, TResult>(this TInput input, Func<TInput, TResult> func)
{
return func(input);
}
string possibleIntInput = ...
int? possibleIntValue = possibleIntInput?.Do(int.Parse);
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!
Just a _crazy_ idea but what do you think about the following syntax:
possibleIntInput !! int.Parse(possibleIntInput)
I'm all for it as long as it works with the rest of C#! (:
Yeah it's a bit tricky. 馃槃
c#
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.
Also, string
is an IEnumerable<char>
so I don't think it would work particularly well at all? Am I missing something?
@niklaskallander Yes, but is string?
one?
@orthoxerox Again, am I missing something?
@niklaskallander it's possible to implement Select
and SelectMany
on nullable types that unwrap the inner value for processing.
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);
}
@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.
It's possible that I'm focusing too much on the example here, rather than the syntax proposal. But the example line:
cs
int? possibleIntValue = possibleIntInput ?! int.Parse(possibleIntInput);
worries me. If possibleIntInput
is "hello"
, an exception will be thrown anyway. Therefore this syntax suggestion will only offer null
protection and will offer that protection by propagating that null
, rather than dealing with it.
I'd prefer to see the team focusing on pattern matching and unions, so an Option<T>
solution could be employed instead:
cs
Option<int> possibleIntValue = int.TryParse(possibleIntInput);
which would yield none
or Some<int>
.
@DavidArno Thanks for your comment. The example is not there for demonstrating the problem I want to solve with the proposal, it is there to demonstrate the syntax of the proposal. A better example might be:
MyResultObject result = myRequestObject ?! PerformTasksFor(myRequestObject);
But as @Unknown6656 said a few comments above the token ?!
should probably be something else as to not confuse it
with a ternary operator followed by a logical not
With language features for both null-coalescing and null propagation I feel that this one is missing.
(And, I'd also like to see more functional concepts in C# such as discriminated unions, immutable record types, forward piping etc.)
@DavidArno Personally, I think that Option<T>
is a lot better than null
because it makes things explicit but it still has its own problems as described here, finally in the case of int.TryParse(...)
the value of None
is inevitably null
so if the parsing failed and you didn't check for it you will still get NRE.
@eyalsk The thing with discriminated unions (Option<T>
) is that you should be forced by the compiler to check for all outcomes = no NRE.
@niklaskallander I understand, I really hope for #5032.
and could possibly create some confusion with a ternary operator followed by a logical not:
a ? !b : c
=/=a ?! b : c
.
I don't see how that could create confusion: a ?! b : c
is a syntax error. What is the :
hanging out for?
a ?! b : c is a syntax error.
No it isn't. It's totally legal syntax today. It would be interpretted as:
a ? (!b) : c
I was thinking if the new operator was valid. Unfortunately it would break existing code like your example.
@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.
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
I often have the pattern of
identity.HasPermissionX ? new X(...) : null
and new X(...)
is usually some multiline db query linq statement and that :null get's thrown at the end.
with this i could change it to
identity.first(p > p.name == 'can do x') ?! new X(...)
so it'd be cool if the left hand side could treat false as nully (or null as falsey)
I need this feature. But my proposition about alias is !??
like opposite to ??
car.vendor = vendorId !?? getVendorById(vendorId)
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
car.vendor = vendorId == null? null: getVendorById(vendorId)
but my first examlpe looks better =)
!??
is already legal syntax in use today
!??
is already legal syntax in use today
and what does it do? My VS does not recognize it
and what does it do? My VS does not recognize it
x!??y
would suppress NRT annotations on 'x' (!
), and then perform the coalescing operation (??
).
This is possible in JavaScript using the &&
operator. Would love to see something similar added to C# :)
console.log(null && "Foo") // null
console.log({} && "Bar") // Bar
I would say ?:
makes the most sense (since if your remove the null
's and whitespace from foo is null ? null : "foo"
that is what is left) but it already has a different meaning in many other languages which might be confusing.
Most helpful comment
It's possible that I'm focusing too much on the example here, rather than the syntax proposal. But the example line:
cs int? possibleIntValue = possibleIntInput ?! int.Parse(possibleIntInput);
worries me. If
possibleIntInput
is"hello"
, an exception will be thrown anyway. Therefore this syntax suggestion will only offernull
protection and will offer that protection by propagating thatnull
, rather than dealing with it.I'd prefer to see the team focusing on pattern matching and unions, so an
Option<T>
solution could be employed instead:cs Option<int> possibleIntValue = int.TryParse(possibleIntInput);
which would yield
none
orSome<int>
.