-
Notifications
You must be signed in to change notification settings - Fork 1k
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: ?obj
operator for real '!null' check on all nullable types
#545
Comments
Wouldn't this happen only in cases where the overloaded operators are broken? I don't think it's worth adding special syntax just for that case. |
There are simple ways to drop down to get a "real" null check, and I think that the cases are not pervasive. Special syntax here would not be widely beneficial IMO. |
|
The idea of this proposal is not that a new expression is really needed. There are some other ways to achieve the result, as is stated in the initial post. It's rather to unify those ways and to streamline with the other questionmark operators for an overall coherent programming experience. As a (nice?!) sideeffect it can reduce the extensive occurences of Also, let's just image that the questionmark operators are going to work on value types that implement a custom 'HasValue' or 'IsValid' function, or 'IValidatable' interface. Well, that's another sheet of paper, but all three operators would make much sense in that context by offering a homogeneous syntax. |
That sounds a lot like this xkcd. "There are too many inconsistent ways to check for Also, would it really improve "coherency", if the other "just a questionmark" operator, i.e. the ternary operator, behaved differently?
I thought the point of the proposed If you want homogeneous syntax, you could use |
Another pro-argument to me is its nearness to C/C++. A team member has once written that many people who come or came to C# have a C/C++ background. What always bothered me is that C# does not have this nice short syntax for conditionally evaluating null pointers and references, due to its very good type safety. MyClass mc = MyClass::Create();
if (mc) {
/***/
} vs. MyClass mc = MyClass.Create();
if (mc != null) {
/***/
} The simple MyClass mc = MyClass.Create();
if (?mc) {
/***/
} |
Just ran into a problem: class ValueHolder
{
public int Value { get; set; }
public static bool operator ==(ValueHolder left, ValueHolder right)
{
if (left == null || right == null) return false;
return left.Value == right.Value;
}
public static bool operator !=(ValueHolder left, ValueHolder right)
{
if (left == null || right == null) return false;
return left.Value != right.Value;
}
}
// Following statement causes stack overflow:
if (f == null) { ... } Well, obviously the operator is broken, should have used public static bool operator ==(ValueHolder left, ValueHolder right)
{
if (?left && ?right) return left.Value == right.Value;
else return false;
} |
I have no idea why that would be the case... |
@CyrusNajmabadi I mean that |
I'm not really understanding the point of this proposal. The 'problem' as stated doesn't seem to actually be a problem. |
But what problem is this actually solving? We don't have people complaining about this. And, indeed, many people like that C# makes the checking explicit. If you're going to introduce a way to do the same thing that can already be done, it needs to add substantial value to the language, or it needs to address some significant issue. Neither seems to be an issue here. |
The problem was that it caused a stack overflow. On first sight |
@lachbaer We already have several ways in the language/platform for people to do comparisons. Including: x == y
x is y
x.Equals(y)
Equals(x, y)
ReferenceEquals(x, y)
EqualityComparer<T>.Default.Equals(x, y) I struggle to think why we'd need something new. Especially something which doesn't seem to do anything that isn't already accomplished with existing functionality available. At best it just seems to muddy things and make the language more complex and confusing for someone to pick up and use effectively. -- Finally, i would ask why we woul dgo and make a special language construct for the case of "If you want to do a real null check" (especially when "is null" exists already). I'm struggling to think when you'd need this. You can already do "is null" or "== null". And if "==" is overloaded, then it's probably appropriate for you to be calling the operator. And, in the rare case, where it isn't, the existing forms are more than sufficient. -- In other words, we're not going to try to make the language more complicated for a use case that is already covered with existing constructs, and which users would barely ever use. We want to invest our efforts into cases that are overwrought today, but which would find value in much of a users code. |
That's not a problem worth creating new syntax for. Just use And these stack overflows are so rare, and so easy to fix, it's not worthwhile to add a whole new language feature (which likely won't actually help people avoid this anyways). |
Just to mention, IDE could help with that by using a different color on user-defined operators. |
No, it's Besides, putting the negating |
@CyrusNajmabadi How about introducing a |
How about using real words, so that people can understand them? |
@dstarkowski You saw the rofl smiley at the end? 😉 |
@lachbaer Yeah I did. Thought it was clear I mixed your words as a joke to sum up what I think about this proposal. But I see I need to explain.
Real words. Even better, grammatically correct sentence.
Real words again. Not a sentence but very obvious.
What!? |
@dstarkowski Your confused smiley made me think that you took my comment literally and conciously. To ride on your wave, you cannot tell from |
Comparing to Same goes for This discussion is about obvious one-liner already in the language vs less obvious one-liner that needs to be added to the language. |
Without considering the double evaluation of the first operand: c = a ?? b;
c = (a is null) ? b : a; or with one time evaluation var tmp = a;
c = (tmp is null) ? b : tmp; Maybe there are some more details in the back, but to me as the stupid user those two are equal in outcome. |
@lachbaer You're right about that example. Was thinking more about exceptions, but now you can throw in ternary operator as well. |
So you take back that statement? 😉 |
they are not. in case of a nullable value type, |
I could have mentioned that I meant classes. 🙄 Also I said "stupid" user, who doesn't care about the inner details. |
This is not an "inner detail", the type of the expression clearly differs. That's just what I'm pointing out. |
@lachbaer Sure, the part about no short alternative to Doesn't change the fact that new operator doesn't introduce any significant value.
Not an inner detail.
|
"Stupid user" wants a |
Today this proposal has no support and won't have for the next releases. |
You can do that today like so: public static class NullStuff
{
public static bool nis(object o) => !(o == null);
}
...
using static NullStuff;
if (nis(o)) ... |
@CyrusNajmabadi Did you get by the rofl smiley that that statement was meant ironically? 😉 |
Nope. Didn't realize that. But my point still stands. It seems really unnecessary to need a new piece of syntax here to handle such an uncommon case. If you want a helper for this, just write one :) |
You see, you don't understand me... 🎉 😆 😛 😉 |
@lachbaer To be fair to everyone, text is an extremely lossy communication medium and you have to take steps to compensate for that. |
@jnm2 like emoticons? 😉 I had a private communication with @CyrusNajmabadi about that, so that one's kind of an "insider". |
@lachbaer Emoticons sometimes help but they can be just as easily misunderstood as text to be honest. |
Yeah, i did not pick up on that at all. -- Anyways, my core takeaway about this bug is as follows:
If you're really just trying to make one tiny area slightly better, for a use case that only you have, then it's almost certainly never going to be something we add to the language. |
No bother at all. 😄 Don't take me too serious, I'm very understandable regarding language issues.
You see, that I don't really get. I absolutely cannot imagine that nobody other than me likes the C-style non-null checks and all 🎉 celebrate the explicit |
@whoisj In another thread you wrote
What's your opinion on shortening the non-null checks? |
I'm sure people like it. But over the 15ish years we've been working on this, the feedback about this issue has been almost non-existent.
It's pretty common for people to come to a new language and want it to be like the language that they're already comfortable with. Most people though simply learn how things are different and internalize it. When other languages provide significant value (i.e. not a reduction of a tiny number of characters), and that value would be widespread (i.e. you'd expect to see it show up in a significant percent of code of a significant percent of projects), then it's worth working on. For the case of just being able ot restate something that is already extremely easy to state, and for the use-case of a very strange operator that i don't think you're writing properly in the first place, then this is just not proving it's worth. -- Here's another way to help think about it. When we look at a new language feature, it usually assumed to be a huge net negative to start with. i.e. all the cost that would have to be poured into designing/implementing it. All the updates to documentation. All the training. All the confusion you now have in the ecosystem. The bifurcation. etc. etc. So, for us to do a language feature it has to provide huge value to even get over the net negative it starts with. Huge value. If it can't demonstrate that, it's not going to happen. Right now there is a completely reasonable way to do a null check |
I've been with C# from the very start - just not frequently. All the other times I've been doing VB(A) 6, C(++) and PHP. But I don't really like VB any more, not even the current .NET version. Nevertheless, it could've been that many people come and say "Hooray, finally somebody who makes this |
This would be incredibly handy. Consider a list of objects that could have null data that you want to compare against - if the null coalescing could also evaluate to false when checking objects then the code would be much cleaner. Search Movies Before
Potential Search Movies After
|
It would be a breaking change to modify how that operator behaves, and it would contradict the design that it always returns a nullable value. In the cases above the result of the expression would be // Search Movies
toReturn = this.Movies.Where(movie =>
(movie.Name?.Contains(searchTerm) ?? false)
|| movie.Actors?.Any(actor =>
(actor.FirstName?.ToLower().Contains(searchTerm) ?? false)
|| (actor.LastName?.ToLower().Contains(searchTerm) ?? false)
)
); |
It seems to me the |
And |
Proposal:
?obj
operator for real '!null' check on all nullable typesIntro
The null-considering operators
??
and?.
become increasingly popular.T?
type with a questionmark indicator.It would be a consistent experience to have a
?obj
operator, that makes a real non-null check on nullable types, reference and value.Problem
null
checks are usually be done by comparing the object tonull
.This is what probably most programmers will write.
However, because there can be overloads of
operator ==
andoperator !=
those checks can be violated and a real comparison tonull
is not achieved.If you want to do a real
null
check, then for reference types you must useFor Nullable value types it is
All toghether this is not a homogeneous experience for the C# user. Also it can lead to unwanted results, in case of operator overloading.
Proposal
The introduction of a not-null-comparison operator
?obj
would unify the "not null check".The not-null-operator checks the resulting object of the right adjacent expression - usually already an object identifier - if it is not a
null
reference or if itHasValue
for Nullables.Misc
I choose
?obj
to be a non-null check, because the other questionmark-operators could be seen as such in a verbal sense. The null-conditional operator?.
proceeds when the object is not null, the null-coalescing operator makes a positive return of its first operand if it is not null.Because the
?
stands at the very beginning of a boolean expression I guess it should be possible to parse it without unresolvable ambiguities.The operator precedence can be like the boolean negating operator
!
and other unary operators.The text was updated successfully, but these errors were encountered: