-
Notifications
You must be signed in to change notification settings - Fork 65
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
Null-conditional operator doesn't work with Nullables #572
Comments
C# has the same issue too! |
The ? Operator turns it from a |
This is confusing! |
The ? Operator doesn't work for classes either for operators. |
I suggest to allow accessing the |
VB has its logic. This will run:
as Nothing will be considered the default DateTime |
Got it but still confused :) |
You can just write If d > Now Then ... |
I faced a practical situation in #576 related to this. result.ToList.Append(New With {
Key .ValidDate = If (rcvValidDate is Nothing, Nothing, rcvValidDate.Value),
Key .Amount = CDec(rcvAmount)
}
) the Append method expects an
So, I have to use this weird long confusing expression: Of course anonymous types should be enhanced, but nullable values should also allow |
result.ToList.Append(New With {
Key .ValidDate = rcvValidDate,
Key .Amount = CDec(rcvAmount)
}
) Does this not work? |
Perhaps you want |
No. It gives:
but this works: result.ToList.Append(New With {
Key .ValidDate = CDate(rcvValidDate),
Key .Amount = CDec(rcvAmount)
}
) |
|
Sorry to hijack but I ran into something similar this week: Public Class Foo
Public Property BarList As List(Of String)
Public Function ShouldSerializeBarList() As Boolean
' Fails
Return BarList?.Count > 0
' Works
Return BarList IsNot Nothing AndAlso BarList.Count > 0
End Function
End Class |
I faced this situation before, and we had long discussion about it. but I can't find the link to the issue. VB.NET returns a nullable Boolean ( |
' Fails
Return BarList?.Count > 0
' Works
Return BarList IsNot Nothing AndAlso BarList.Count > 0 these are not hte same. the first is (effectively in pseudocode):
This means you can return either null or a boolean (or, a The second says:
This means you only ever return a boolean. This is ok as that matches your method. There are many ways you can fixup your code. Which is "the right way" depends entirely on what you're trying to do. |
@CyrusNajmabadi so, in either case, the conversion from Nullable Value to the normal value is valid, and it is wrong to treat VB as C# in this situation. |
@VBAndCs I'm sorry, this is incorrect, and is the same line of thinking as in dotnet/roslyn#48387. In VB, it is a narrowing conversion to go from https://github.com/dotnet/vblang/blob/master/spec/conversions.md#narrowing-conversions
As such, with
I never said anything about C#. I was speaking entirely about how VB treats things here. I highly recommend you read through the other issue and also through the language specification here. It seems like it would be very helpful for understanding this issue and not getting tripped up over this concept. Thanks! |
Just wanted to mention a couple of notes on things from across the discussion. First, remember that Next, when doing math or comparison operations with nullable values ( Now, when you want to turn that
|
Fantastic! The exception happens even when But this goes beyond option strict. This code will throw despite using the CBool:
What I am saying here. is that the unlike C#, conversion from vtype? to vtype is possible in vb and perfectly safe, and should be allowed implicitly and explicitly. |
@gilfusion
but this runs OK:
despite that both |
@gilfusion @CyrusNajmabadi
in the expression |
This also woks fine even with `Option Strict On' Dim b1 As Boolean? = Nothing
Dim b2 As Boolean
If Not b1 Then
b2 = False
Else
b2 = True
End If but |
In fact, all operation on nullable Boolean works fine in f statement: Dim b1 As Boolean? = Nothing
Dim b2 As Boolean
If b1 AndAlso b2 Then
b2 = True
ElseIf b1 OrElse b2 Then
b2 = False
End If but fails elsewhere. |
Note that C# doesn't accept bool? b1 = null;
bool b2;
if (!b1)
b2 = false; |
@VBAndCs, ultimately, I think the confusion goes back to the VB7/8 timeframe went from one meaning to three. Here is some VB6 code I was just tinkering with: Dim myVar As Variant
Dim myBool As Boolean
Private Sub cmdEmpty_Click()
myVar = Empty
myBool = myVar
End Sub
Private Sub cmdNothing_Click()
myVar = Nothing
myBool = myVar
End Sub
Private Sub cmdNull_Click()
myVar = Null
myBool = myVar
End Sub Back then, In VB7 (.NET 1.0), the meaning of In VB8 (.NET 2.0), nullable types were added, and, when using nullable intrinsic types, So, the problem I think you're having with |
So based on the above, this works with the XmlSerializer in all cases: null list, empty list, non-empty list Public Class Foo
Public Property BarList As List(Of String)
Public Function ShouldSerializeBarList() As Boolean
Return (BarList?.Count > 0).GetValueOrDefault()
End Function
End Class So what's the verdict...bug or not? Edit: |
@gilfusion
You expect to see: |
My suggestion here, to give error on any condition using nullable directly without |
This is where it would have to happen. VB has always been very strong on backward compatibility and not introducing breaking changes. VB today works with nullables the way it has for years. And we know that Microsoft are not about to change it. This discussion, along with the discussions around 'non-nullable' vs 'nullable' reference types (mostly in C#, but also here #355 and #386 ), suggests to me that some of these concepts were not fully considered at the time .NET was being developed, and both VB and C# have inconsistencies in their treatment of null-related activities. However, we are where were are, and fixing it will likely break a lot of existing code. Personally, I've don't have a problem with the status quo, because it is clear what the code is doing if you don't try to minimize the code. If you have a 3-state variable (Nullable(Of Boolean)), then you need to test all three states. If you don't need three states, then don't use a nullable boolean. Dim b1 As Boolean? = GetTheValue()
If b1.HasValue Then
If b1.Value Then
' do the true thing
Else
' do the false thing
End If
Else
' do the null thing
End If has always been the way I deal with a nullable. Of any kind, because that's kind of the point of them. As for:
That is completely subjective, and I disagree. It makes perfect sense to me. In fact, I find it is If d doesn't have a value, then why would you compare it to another value? Remember that a syntax for a value type needs to be consistent for all value types. Does your proposal make sense if you replace 'Date' and 'Now' with any other value type instead of 'DateTime', and some other value instead of 'Now'. I would suggest that the answer is 'no', because the semantics of such a construct would be completely dependent on what the author of the value type decides is the default value. Which need not be a constant. Going back to your If If(d, DateTime.MinValue) > Now Then ... which also allows you to pick the default value you want, instead of relying on the type's default. Since DateTime.MinValue is also the default value for a DateTime, it should also work here: result.ToList.Append(New With {
Key .ValidDate = If (rcvValidDate, DateTime.MinValue),
Key .Amount = CDec(rcvAmount)
}
) |
This has been how the language has worked for the last 15 years. Any new behavior would be even more unexpected than the behavior which has been the norm since literally VB 8.0. |
They were definitely considered at the time, and many options were considered. The choices we made here reflect our thinking back then on what we felt was appropriate for this sort of type. |
VB booleans are a tri-state system. That's why you use them. If you just want two states, use |
This is exactly the problem: you invented different rules for each language! This is illogical :) |
They are different languages. If they had the exact same rules there would be no point using one over the other. This is why multiple languages exist. :) If you just want C# semantics... use C# :) |
Just another practical case that shows the agony caused by current design: |
And another one: The expressions containing A side note: |
Dim _ItemIDs As List(Of Integer)
Dim Value As Integer = 10
Dim i = If(_ItemIDs?.IndexOf(Value), 0) I'm too lazy to write a whole function for GetOriginalValueFunc, and you don't say explicitly what you're expecting. But I suspect this will work (or at least produce the same result). Return Me.SelectedID <> If(GetOriginalValueFunc()?.Invoke(), 0) Using a null-coalescing If(..) also gives you an opportunity to specify your own default that is not the Type's default, which I think makes it more useful than GetValueOrDefault(). |
Posting here won't change this. If you want the language to change, open a issue where this can be discussed and evaluated. Do not reuse existing issues (which have been addressed) to bring up new things you want changed. |
That question is better suited to dotnet/roslyn. VS ide behavior is not really part of the vblang repo. Thanks! Note: if you wanted to create a PR to address this on dotnet/roslyn, it would very likely be accepted. |
@ |
@CyrusNajmabadi I posted the issue in Roslyn: dotnet/roslyn#48581 |
We accept dozens of community contributions per sprint. These also include many VB improvements. In general, we only take improvements if they also handle the VB side as well. And if that's out of scope for the community member, we'll pitch in to do that work ourselves to ensure that VB and C# both get the improvement. |
This is offtopic for this issue. If you want to talk about new things please either file a new issue, or take the discussion to a community forum like gitter or discord. Future posts on this issue that continue this will be marked off topic. This is important as it affects our ability to manage and track these topics through issues. By taking things off track, or using closed issues, it effectively subverts that ability. Thank you. |
I get the error:
Why doesn't the
?
operator work with nullable values?I think it should.
The text was updated successfully, but these errors were encountered: