Skip to content
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

CDate(CStr(Nothing)) should not cause an exception #621

Open
jrmoreno1 opened this issue Mar 2, 2023 · 5 comments
Open

CDate(CStr(Nothing)) should not cause an exception #621

jrmoreno1 opened this issue Mar 2, 2023 · 5 comments

Comments

@jrmoreno1
Copy link

Just ran into this today, apparently it's a long standing bug: dotnet/roslyn#2780, although I disagree with the recommended behavior.

IMO the correct fix is for the call to Conversions::ToDate(string) to check to see if the string is null, and return DateTime.MinValue if so.

In my case, Option Strict was Off and the actual assignment that caused the problem was obj.d = if(function(a, b)) where sometimes the return value was nothing and sometimes it was a string that could be interpreted as a date. Obviously the better code would be DateTime.TryParse(function(a,b), obj.d), but it shouldn't break.

@rskar-git
Copy link

The Roslyn team said that the VB compiler of Visual Studio 2013 was doing it wrong in the first place: "This is a bug in the constant optimization phase of the old compiler. It was never the intended behavior of the language." I agree with them. For a start, VBA/VB6 never allowed for it. CDate(vbNullString) fails with a type mismatch error. CDate(Nothing) fails with an invalid use of object error. CDate(Null) fails with an invalid use of null error.

So the VB compiler of Visual Studio 2015 (and later) does it correctly; there is no bug to fix.

If one is stuck with a code-base that has "CDate(CStr(Nothing))" issues, really it should be refactored. It was a poor practice to begin with, and one can't even claim it was ever really okay to do that.

@jrmoreno1
Copy link
Author

I think https://dotnetfiddle.net/o1Ws5L shows that it’s a bug….only cBool and CDate throw

 Public Sub Main()
     Dim s as string = nothing
     dim bt =CByte(s)
     dim c = CChar(s)
     dim db = CDbl(s)
     dim d = CDec(s)
     dim i = CInt(s)
     dim l = CLng(s)
     dim o = CObj(s)
     dim sb = CSByte(s)
     dim sh = CShort(s)
     dim sn = CSng(s)
     dim str = CStr(s)
     dim ui = CUInt(s)
     dim ul = CULng(s)
     dim us = CUShort(s)
     Console.WriteLine("no exception")

    try
      dim b = CBool(s)
   catch e as exception
      Console.WriteLine(e.ToString())
   end try
   try
      dim dt= CDate(s)
   catch e as exception
      Console.WriteLine(e.ToString())
   end try
 End Sub

@rskar-git
Copy link

It may be a more compelling case to say that CBool and CDate are correct, and that the CByte thru CUShort cases (not including CStr and CObj) are wrong.

Let CPdq() mean to be any one of these CByte thru CUShort cases. Then something like CPdq(CStr(Nothing)) should evaluate to the same result as CPdq("") - exactly as CBool and CDate do. Why? Because VB.NET idioms should accommodate as many VBA/VB6 idioms as were conceivably possible under the new .NET paradigm. For example, VB.NET has a version of the VBA/VB6 constant vbNullString; hence, CPdq(CStr(Nothing)) means exactly the same as CPdq(vbNullString).

Yet in VBA/VB6, things like CInt(vbNullString), CDbl(vbNullString), and CDec(vbNullString), all result in error. So there is no backward-compatibility case (i.e. going from VB6 to VB.NET) to be made for allowing CPdq(vbNullString) to return a default of "Pdq".

VB.NET, for whatever the reasons, seems to have a special case for CStr(Nothing) to be treated the same as CObj(Nothing) for CPdq(). The Nothing of any other reference type results in error (unless coerced via CObj or however).

It's unclear to me whether this special case for CStr(Nothing) was a mistake or intentional. The one VBA/VB6 idiom that was not quite brought to VB.NET is that of the COM Variant (https://en.wikipedia.org/wiki/Variant_type_(COM)). Maybe someone thought CStr(Nothing) could be a stand-in for the Variant Empty, and make it easier for others to do VB6 to VB.NET translations, especially where a lot of textual processing happens?

Whether intentional or a mistake, I can see why there's a lack of interest and motivation to change CDate and CBool to be more like CPdq.

@jrmoreno1
Copy link
Author

@rskar-git : I’m not looking for VB6 compatibility, but with VB.Net pre-Roslyn. It changes functional code into non-functional. And VB.NET does extra handling with strings and nothing, this is definitely one of the places I, as a VB.net programmer, would expect it do the useful thing, which is to return the default date, aka date.minvalue. Throwing is not helpful.

@rskar-git
Copy link

Well, to each their own, I guess. I still find code like this to be super-cringy:

Option Strict Off
Dim d As Date
d = vbNullString

even if the above would work at run-time in (pre-Roslyn) VS2013 VB.

(Would it be interesting to point out that the reporter of this issue is happily coding in C# and Rust today?)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants