Implicit Interface casts of Nullables - vb.net

With VB's Option Strict On, why does a Nullable(Of T) not require an explicit cast to an interface of T when it does require one to T?
I.e.
Dim x As Integer? = 5
Dim y As Integer
Dim z As IComparable
y = x ' Fails to compile with error
' "Option Strict On disallows implicit conversions from 'Integer?' to 'Integer'."
z = x ' Succeeds
EDIT: As (sort of) shown by #SSS, part of the answer is that Nullable values are, well, nullable, and can be Nothing, which is fine for a reference like an interface. So this conversion will always succeed, unlike the conversion to T case (which fails when the Nullable has no value), and so it can be seen as an implicit conversion.
My question now becomes "how?". How is the conversion from a Nullable(Of T) (which has no interfaces of its own) to an interface of T theoretically negotiated?
I know the implementation is box Nullable<T>, which effectively strips the Nullable wrapper, but I'm confirming the concept here...
(So I'll review the documentation and see if they explain this.)

I don't see the problem?
y = x
can fail because x could hold a value of Nothing, but y is not allowed to hold a value of Nothing. The IComparable interface allows Integers to be compared to Nothing however, so that assignment is fine.
Notice that if you swap it round:
x = y
then this succeeds because every value of y can be assigned to x.
You can confirm that Integers can be compared to Nothing as follows:
MsgBox(5.CompareTo(Nothing))

From what I can tell in vb.net, the statement interfaceVariable = nullableVariable is essentially equivalent to interfaceVariable = if(nullableVariable.HasValue, CType(nullableVariable.Value, interfaceType), Nothing). The C# compiler seems to handle things the same way: interfaceVariable = nullableVariable; becomes interfaceVariable = nullableVariable.HasValue ? (interfaceType)nullableVariable.Value : null;.
If the type of nullableValue.Value implements the interface, then nullableVariable.Value will either perform return a value-type result or throw an exception. Since there exists a guaranteed boxing conversion from the return value to the interface, the cast will be legal. The only way the above code could fail would be if the nullable variable gets written between the calls to HasValue and Value, such HasValue sees the variable as non-null, but Value sees it as null and throws an exception. I believe that writing interfaceVariable = nullableVariable just tests nullity once, so that an exception could not occur; instead, an indeterminate value would get boxed.

Without actually reading documentation yet, I'm going to attempt an answer:
Firstly, the higher-level answer is that casting a Nullable to an interface is "safe" and will not throw, so it is logically a Widening operator and should not need to be explicit (compared to casting to T, when .HasValue is False it throws, so it should not be implicit with Option Strict On).
However, technically the "how" is a bit obscure: Even though some of the behaviour of Nullable is encoded in the metadata available via reflection, much of its "magic" is hidden in:
the runtime behaviour of box on a Nullable (and thus the compiler knows when to leave "lifting" to that), and
the other points made by Eric Lippert in his answer for C# and their equivalent in VB.NET.
It looks like S. Somasegar's blog post announcing changes to Nullable support in a late beta release for VS2k5 is also relevant here.

Related

Kotlin: At which situations does implicit conversion happen?

I am a beginner in Kotlin.
I'm most familiar with Python, and I just read through the basic Java Tutorial https://docs.oracle.com/javase/tutorial/java/index.html before jumping into Kotlin.
A question came up in my mind while reading this section of the documentation of Kotlin
https://kotlinlang.org/docs/reference/basic-types.html#explicit-conversions
What I have understood from above section of the documentation is:
For assignments =, implicit type conversion happens. If the lefthand side's type is a supertype or same type of righthand side's type the code would compile. Otherwise it's a compile error. In case of Int and Long, they are both subtypes of Number but neither of them subtypes of each other, so the implicit conversion would not work. Therefore we need to use methods like .toLong() or .toInt() to explicitly convert them.
Then when I read the part
val l = 1L + 3 // Long + Int => Long
I started wondering if implicit type conversion would be taking place in this situation.
The documentation says this has to do with the operator overloading.
How is this operator overloading implemented under the hood?
I tried to find the source code at Github https://github.com/JetBrains/kotlin/blob/master/core/builtins/native/kotlin/Primitives.kt ,
but here the functions are only declared but not implemented. Where can I find the implementations?
It seems that operation overloading does not actually perform type conversion. Do we just implementing all possible functions with same name but different parameter type signatures, so that the type is inferred, then the function with the matching signature is selected?
And the general question: In Kotlin, exactly at which situations does implicit conversion happen?
For assignments =, implicit type conversion happens. If the lefthand side's type is a supertype or same type of righthand side's type the code would compile.
Assignments aren't special in this. More generally, if the expected type of an expression is a supertype or the same as actual type, the code compiles; it's just that the expected type for the right-hand side of an assignment is the left-hand side's type. I wouldn't say there is an implicit conversion inserted, but I don't think anything breaks if you see it that way.
Do we just implementing all possible functions with same name but different parameter type signatures, so that the type is inferred, then the function with the matching signature is selected?
Yes, exactly (for this case). If you want to support primitive types, you need to provide overloads for all of them.
So 1L + 3 is just a method call so far as the parsing and type-checking is concerned (`Long.plus(Int): Long specifically), no implicit conversion is involved. But these methods are built into the compiler to handle specially which is why you don't see an implementation.
It becomes two bytecode instructions i2l ("convert an int into a long") and ladd ("add two longs"), but that's not something you should probably care about yet, or for a long time.
And the general question: In Kotlin, exactly at which situations does implicit conversion happen?
Smart casts are the closest Kotlin has to implicit conversions but they are sufficiently different from i.c.s in other languages that I wouldn't use the name. So I'd say never.

How serious is BC42020 in an upgraded VB .Net project?

Consider the following line of code which used to compile without warnings.
Public SetUpDone = False
After upgrading a project to Visual Studio 2017 from Visual Studio 2005 over a hundred of these BC42020 warnings exist. The MSDN description of the warning simply states that the variable defaults to type object. I don't have a good idea of the seriousness of this type of warning. The debugger indicates that the code executes as I expect. Is it merely a performance type of issue?
Secondly, I thought that Visual Basic supported some form of Type Inference so I'm not clear about why it wouldn't be able to deduce that the type should be Bool.
Another example is the following where the function returns a String
Dim dayTxt = " " & GetTextFromIni("General", "Var50")
I would have thought that type inference would work here and deduce that dayTxt is a String.
This:
Public SetUpDone = False
Is equivalent to this:
Public SetUpDone As Object = False
As suggested, type inference is only for local variables, not fields. With Option Infer On, this inside a method:
Dim SetUpDone = False
would indeed be equivalent to this:
Dim SetUpDone As Boolean = False
There are a couple of issues with the code as you have it. Firstly, it means that every use of that False value requires unboxing which makes your code slower. That's the case for any value types, i.e. structures. Value types are normally stored on the stack but, when boxed, are stored on the heap.
Secondly, it means that any member access will require late binding. That's not an issue for Boolean values because they have no members of interest anyway but if it was, say, a DateTime then the IDE would never provide Intellisense for that type because al it would see would be type Object and the existence of the specified member would have to be confirmed at run time, making the code less efficient again.
Thirdly, it means that the compiler can never confirm that you're passing the correct type as a method argument. For instance, if you have a method with a Boolean parameter, the compiler won't know that you're passing a Boolean if you pass that field because it's type Object. That also means that if you pass some other Object variable that doesn't contain a Boolean, the compiler can't warn you.
As suggested, you should turn Option Strict On in the project properties. That will flag every instance of you're not specifying the appropriate type for something. Fixing those errors will, at the very least, make your code a bit more efficient. It may even draw your attention to situations where exceptions will or could be thrown at run time. Having Option Strict On enforces strict typing so it makes you think more about the types you're using. Even if you're conscientious about that with Option Strict Off, you can still make mistakes that Option Strict On will prevent.

Turning on Option Strict - Pitfalls?

I'm turning On Option Strict on all project in my newly inherited VB.NET application. I'm mostly adding alot of CStr, CBool, CType statements to get rid of all the compile errors.
Dim x As String = someObject
dim val As SomeEnumType = 1
becomes
Dim x As String = CStr(someObject) ' Not .ToString() because someObject could be Nothing
Dim val As SomeEnumType = CType(1, SomeEnumType)
etc.
I'm doing everything pretty much by hand one error at a time and have a test application to test the Nothing, ... bordercases.
But is it possible I'm missing something that is going to generate exceptions at runtime?
And what kind of code is being generated due to Option Strict? Is it just some conversions that are going to be added or does OptionStrict do other things aswell?
Option Strict On does not generate any extra code, it merely tells the compiler to generate errors when your vb.net statements are relying on implicit type conversions. Like assigning an object to a string. What you've written in your snippet is exactly what the compiler does with Option Strict Off so no extra code is generated by your type conversion operators.
But of course, there's always a non-zero chance that you use the wrong conversion and break the existing code. You'll have to do what's always required when you make changes to code, you'll have to re-test it.

Is it good practice to define "what my variable will be"?

So I have this:
Dim aBoolean As Boolean = True
Will it make any difference to just do this?
Dim aBoolean = True
In other languages, I believe it was a good practice to also define the type of variable it would be, for performance or something. I am not entirely sure with VB.NET.
Thanks.
It depends. Explicitly defining the variable can improve readability, but I don't think it's always necessary. (To be clear, it has nothing to do with the actual functionality of your code).
In this specific example, you follow the declaration with a Boolean assignment of True, so it's already crystal clear that aBoolean is actually a Boolean when it is declared. The As Boolean syntax is not as necessary in this scenario.
Other cases may not be so clear. If the declaration was followed by the result of a function call, for example, it might be more clear to explicitly declare that the variable is a Boolean. e.g.
Dim aBoolean As Boolean = TestValidityOfObject(o)
As long as you have Option Infer turned on, it won't make a bit of difference. The second line is just a syntactic abbreviation for the first. At that point, it's up to your style preference as to which you should use.
Before type inference, there were performance issues when not declaring the type, but that's no longer an issue; due to type inference the variable will be of type Boolean whether you declare it or not.
Declaring the type can help the compiler catch errors sooner, and will often give you better Intellisense.
You're using what's called "type inference". This is where the compiler figures out at compile time what the type on the right side of the assignment is and uses that as the type of the variable.
This is, in general, a safe and convenient feature. However, there are a couple of things to keep in mind:
You must have Option Infer on; otherwise, the compiler doesn't do type inference and, depending on your setting for Option Strict, instead either gives you a compile time error (Option Strict On) or types your variable as Object and uses late binding everywhere. This is Pure Evil. (Option Strict Off)
In your particular case, there's no way for the compiler to mess up. HOWEVER, it's possible to use type inference in such a way as to change the semantics of your code:
For instance...
Dim myClass as MyBaseClass = New SubClass()
This is perfectly legal; we're typing the variable as a base class and assigning a value to it that represents an instance of a subclass. Nothing special. However, if we switch to type inference by just removing the type declaration...
Dim myClass = New SubClass()
Type inference will now see myClass as a SubClass instead of MyBaseClass. This might seem obvious, but the point is that you should be aware of what it's doing.
For more information and long-winded discussion about using type inference, see this question. While that question is targeted at C#, the only real difference is the first item that I listed above. Everything else is conceptually the same.

Why use TryCast instead of DirectCast?

When I am trying to cast Object obj to Type T, if it can not be cast then there is something wrong.
And after I cast the object I will be looking for working with the cast object.
Rather I will be expecting to get an exception at the place where I will be casting it than say where I will be using that object.
In this sense, is it better to use DirectCast instead of TryCast?
Or am I missing some other significance of using TryCast?
(For C# developers, TryCast is similar to "as" and DirectCast is the equivalent of normal casting. As Mike pointed out in the comments, "as" works for nullable value types, but TryCast doesn't.)
If the value really should be a T, then DirectCast is indeed the right way to go - it fails fast, with an appropriate error.
TryCast is appropriate when it's legitimate for the target to be the "wrong" type. For instance, to get all the Button controls in a container, you could go through the control collection and try to cast each to Button. If it works, you do something with it - if it doesn't, you move on. (With LINQ you can just use OfType for this purpose, but you see what I mean...)
In my experience direct casting is appropriate more often than TryCast - although with generics I find myself casting a lot less often than I used to anyway.
The only difference between the two is that, a TryCast will return a null if it fails, while a DirectCast will throw an exception.
These has implications on how you can handle your program. Personally I prefer not having to throw an exception if the possibility of an improper cast (e.g., text input boxes for user input being cast into numeric types) is pretty high.
I think the others have mentioned the times when you should and shouldn't perform "safe casting" (where you ensure that the cast can succeed before risking an exception). If your program does need to perform safe casting then the TryCast method saves both you and the program some work.
I wasn't aware of the TryCast() function until today, and I feel like a fool for using the 'bad' method of safely casting.
If you did not know about the TryCast() function then you might end up with something like this:
'' wasteful, the TypeOf and DirectCast calls are redundant
If TypeOf obj Is SomeClass Then
someObj = DirectCast(obj, SomeClass)
'' More code
End If
The problem is that this method actually performs two casts (technically I think they're actually type-checks). Using the TryCast and checking if the result is Nothing eliminates the 2nd cast and saves needless work.
'' efficient, only one cast is ever performed and there are no InvalidCastExceptions thrown
someObj = TryCast(obj, SomeClass)
If someObj IsNot Nothing Then
'' More code
End If
Following this pattern lets you avoid having to handle expensive exceptions, and efficiently cast to the correct type.
If your design mandates that the object passed to you MUST be of type T, then assert (as in Debug.Assert) that the cast succeeds in debug builds and run exhaustive unit tests to prove that your implementation follows your design.
With your design proven and tested, you can perfrom the direct cast knowing that it can never fail.