0

C# guys will excuse me for VB, but the following should be related to both languages. EDIT: It is related but no-one noticed so far that C# and VB evaluate differently. Question adjusted.

Before, if we had simple

If condition Then
    ThenPart()
Else
    ElsePart()
End If

and wanted to re-arrange it into reverse order, we swapped ThenPart() and ElsePart() and negated the condition (generally speaking, by using Not(condition)). It was possible to re-arrange every condition.

Recently, great Null-conditional Operators were introduced. And with them assymetry came into conditions. You can no longer use Not(condition) with them. Or am I overlooking something? (This is the question.)

Try re-arranging ThenPart() and ElsePart() into reverse order here:

Dim list As List(Of Integer) = Nothing
If list?.Count > 0 Then
    ThenPart()
Else
    ElsePart()
End If

The trick is that null value appears in condition and of course, it cannot be negated using Not. Therefore you cannot use trivial negation If Not(list?.Count = 0) nor you can use If list?.Count <= 0.

The only way is old-fashioned If list Is Nothing OrElse list.Count = 0. (Exact negation would use <= 0) (Edit: Applies only to VB. VB and C# diverge here, see below.)

Trivial times where it was simple to negate every operator are gone (edit: only in VB). Or am I overlooking something?


After additional research:

It looks in the C# you can safely do !(list?.Count = 0) and after this finding, C# got out of this question. No asymmetry here, you can negate as before. But as far as I can see, the asymmetry remains with VB because of null evaluation in Visual Basic which is similar to ANSI SQL – null value propagates through the expression. So in VB, you cannot negate list?.Count > 0 more trivially than If list Is Nothing OrElse list.Count = 0. (That's why I used word 'asymmetry'.) Or am I overlooking something?

Community
  • 1
  • 1
miroxlav
  • 11,796
  • 5
  • 58
  • 99
  • This case resembles `TypeOf ... Is ...` statement where form `TypeOf ... IsNot ...` was missing many years, while `IsNot` was already present all the time, but could not be used. But that time, negation using `Not` was trivial. Anyway, these gaps inadvertently move VB to place of second-class citizen. The `?.` seems to create similar case, too. But will language team find introducing of negated form of `?.` reasonable enough? Especially if C# does not need it. – miroxlav Aug 11 '15 at 09:28

2 Answers2

3

You should be able to negate condition just fine:

 if (!(list?.Count > 0))...

But there is no short form for negated one (you have to live with expanded form).

There is nothing new in relation to moving negation into condition (except you got shorter way of writing x != null && x.Count > 0 as x?.Count > 0) - same Morgan laws apply to negate.

Original condition (A and B):

 list != null && list.Count > 0 

Negated (not A or not B):

 list == null || list.Count <= 0

Note that similar behavior exist in C# 5 for nullable values - if you negate just operation (like > to <=) you get wrong results:

int? v = null;
Console.WriteLine(v1 > 1); // false
Console.WriteLine(!(v1 > 1)); // negated, so true
Console.WriteLine(v1 <= 1); // just > negated - false.
Alexei Levenkov
  • 98,904
  • 14
  • 127
  • 179
  • This is clear, but De Morgan laws keep me away from `?.`. I always need to expand `?.` before negating, right? This was my point. Is there no way to keep them? From this viewpoint, `?.` operator seems to be a bit half-baked. – miroxlav Aug 10 '15 at 22:10
  • @miroxlav as I've said in post I don't think there is any syntax sugar for negated version. Note that I'd simply use R# and let it deal with negation - likely will do it automatically for you. – Alexei Levenkov Aug 10 '15 at 22:11
  • OK, this was my point with `?.` syntax sugar. It has no support for negation... So bye-bye to previous concept where all operators could simply withstand negation. This is why I gave title `...first asymmetry in conditions introduced?` – miroxlav Aug 10 '15 at 22:14
  • @miroxlav "first"? - `int?v = null; if (v > 0)...` was there for some time. The syntax sugar generally introduced for cases frequently encountered in code and rarely with goal of supporting all possible operations. I rarely see a person who can easily read or conditions like - `list == null || list.Count <= 0`, so I'm not surprised about lack of syntax sugar for it (as it likely will be even more confusing). – Alexei Levenkov Aug 10 '15 at 22:25
  • (Also not sure what is wrong with `!(list?.Count > 0)` - not really readable, but syntactically correct) – Alexei Levenkov Aug 10 '15 at 22:28
  • 1
    I've found the culprit: **C# and VB evaluate differently**. There is really no difference in C# and you can safely use negation `(!(list?.Count > 0))`. Bot you CANNOT in VB. While C# catches `null` value at first comparison (`null > 0`) and the result is Boolean, in VB, `Nothing` is propagated trough operators so final result of the same is not Boolean – but Nothing! So negation cannot be made. My bad that I included C# into this question in false assumption it works in same way... but obviously there is a big difference. "Symmetry" in C#, but "asymmetry" in VB (=you cannot simply negate). – miroxlav Aug 11 '15 at 08:02
  • @miroxlav - it may be better to ask that as separate self-answered question like "why negation of null-conditional operator does not work in VB.Net (compared to C#)" as it sounds interesting by itself (unless already answered on SO). – Alexei Levenkov Aug 11 '15 at 16:29
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/86727/discussion-between-miroxlav-and-alexei-levenkov). – miroxlav Aug 11 '15 at 19:25
3

Trivial times where it was simple to negate every operator are gone.

Nothing has changed - if condition could return null in your first example then you could not simply swap the if and else parts. Adding null to the mix prevents simply using Not regardless of the new operator.

It's not the fault of the operator - it's the fact that a nullable boolean is not symmetric.

D Stanley
  • 149,601
  • 11
  • 178
  • 240