Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I prevent the comparison of Enum with Integer?

Tags:

enums

vb.net

I am using an Enum type with the object of preventing spurious values being used:-

Public Class MyClass1

    Public Enum MyEnum As Byte
        FIRST
        SECOND
    End Enum

    Private my_var As MyEnum

    Public Property MyVar As MyEnum
        Get
            Return my_var
        End Get
        Set
            my_var = Value
        End Set
    End Property

End Class

Public Sub MyWorks

    Dim my_object As MyClass1 = New MyClass1

    my_object.MyVar = 1      ' Compilation Error
    my_object.MyVar = 33     ' Compilation Error

    If my_object.MyVar = 1 Then       ' No Compilation Error
    End If
    If my_object.MyVar = 27 Then      ' No Compilation Error
    End If
    If my_object.MyVar = 3.141 Then   ' No Compilation Error
    End If
    If my_object.MyVar = "Fred" Then  ' Compilation Error
    End If

End Sub

(This compiled with Option Strict On; Option Explicit On.

As I expected, the attempted assignments to the Enumeration property produce compilation errors ( Option Strict On disallows implicit conversions from 'Integer' to 'MyClass.MyEnum').

But the first three comparisons do not, where I was rather hoping they would (especially the second and third, which are nonsense). The fourth comparison doesn't compile but the error message seems strange:-

Option Strict On disallows implicit conversions from 'String' to 'Double'.

Does anyone know how I can force compilation errors to appear for all of these comparisons?

like image 914
Brian Hooper Avatar asked Sep 29 '22 14:09

Brian Hooper


1 Answers

    my_object.MyVar = 1 ' Compilation Error

Reason :
my_object.MyVar is of type MyEnum, and 1 is of type Integer (Byte/UShort/Etc.) So you have a compilation error with Option Strict On. Use this instead :

    my_object.MyVar = MyEnum.SECOND
    ' .SECUND should mean "1" as FIRST would be "0" by default..

But why ? "1" should be of type Byte since you've explicitly "strong-tiped" your enum..! Well, you can't assign a literal integer (Byte) value anymore to an enum once Option Strict is On. With Option Strict Off, it works ! But you may wonder why with Option Strict On, the following also works :

    Dim MyByteVar As Byte = 1 ' No compilation error

The MyByteVar is of type Byte, and without any Type Character identifier after the litteral value, the litteral "1" is assumed to be of type Integer. But because the compiler knows MyByteVar is of type Byte, it tries to convert "1" to a Byte and it works. Not compilation error occurs.

So don't confund the narrowing conversion with the explicit type mismatch. Converting "1" to the type MyEnum wont work with Option Strict On, not because the compiler can't convert 1 to a matching value in the enumeration, but because the compiler shouldn't even try that. The main purpose of explicitly strong types declaration and strict type assignations is to avoid such risks as stated on the MSDN Option Strict Page. AndAlso, on the MSDN Page about Enumerations, you'll have similar statements :

WRONG I'm sorry, I was fooled by another issue I encountered last week. You just can't make narrowing conversions (Integer -> Byte) with Option Explicit On.
EDIT 2 : ^^ seems I was right after all :/ Well, I'm unsure to be honest, sorry-sorry..

  • Reduces errors caused by transposing or mistyping numbers.
  • Makes it easy to change values in the future.
  • Makes code easier to read, which means it is less likely that errors will be introduced.
  • Ensures forward compatibility. If you use enumerations, your code is less likely to fail if in the future someone changes the values corresponding to the member names.

There is no reason to have created Enumerations, Option Strict and Option Explicit if you're okay with Dim my_var As MyEnum = 1. Those security checks are there to make your code/coding safer, narrowing by the way the amount of liberty to write anything.

    If my_object.MyVar = 1 Then
    ' my_object.MyVar = MyEnum.FIRST = 0 -> Byte (strongly typed)
    ' 1 -> Integer by default
    ' Convert my_object.MyVar to Integer (always a widening conversion)
    ' 0 is different from 1 (Integer to Integer comparison)
    ' -> FALSE - No compilation error


    If my_object.MyVar = 27 Then
    ' Same as above and will return FALSE

    If my_object.MyVar = 3.141
    ' my_object.MyVar = MyEnum.FIRST = 0 -> Byte (strongly typed)
    ' 3.141 -> will default to Double (because you didn't used Type Character flag)
    ' Convert my_object.MyVar to Double (always a widening conversion)
    ' 0 is different from 3.141 (Double to Double comparison)
    ' -> FALSE - No compilation error

If you've set the value of my_object.MyVar to MyEnum.SECOND, the following will not produce a compilation error, and will compare to TRUE :

    If my_object.MyVar = 1
    ' my_object.MyVar = MyEnum.SECUND = 1 -> Byte (strongly typed)
    ' 1 -> will default to Integer
    ' Convert my_object.MyVar to Integer = 1
    ' 1 = 1 => TRUE !

The following is pretty much the same as for the Byte assignation thing :

    If my_object.MyVar = "Fred" Then '...

With Option Strict On, there is no such conversion from Double to String allowed. This is an obvious type mismatch and Option Strict forbid that. But why Double and not Byte ? Because the Compiler tries one widening after another while attemting to get a type match. Byte -> Integer -> Long -> .. -> Double.

Either you shoud explicitly convert my_object.MyVar to a String, either explicitly convert "Fred" to a numeric value. The comparison test will always try to take care of required widening conversions (whenever possible) but only the basic widening ones are allowed with Option Strict On.


So how to make your code fail upon compilation for the first three row of comparison. Well, I don't know. Perhaps it's worth questioning what is allowed with Option Strict and what is not, so I think that's more a philosophic question than a practical one.

=> Should an expression/evaluation that returns a boolean forbid comparison between numbers of different types ?
=> Should basic widening conversions Byte -> Double be forbidden when Option Strict is On ?

I'm sorry, I'm not qualified to answer such questions...

like image 195
Karl Stephen Avatar answered Oct 05 '22 06:10

Karl Stephen