Cannot use a bitwise And with a negative number - vb.net

It appears that any bitwise operator with a negative number won't happen. Even something as simple
Dim b As SByte = CSByte(-128 And &HFF)
But the computer returns "Constant expression not representable in type 'SByte'" Why would that not work? Just to be safe, I tried to surround it with a conversion. SByte as -128 is 1000 0000 and &HFF is 1111 1111. Line them up and
1000 0000
1111 1111 And
1000 0000
Which is still -128 and legal for SByte. What am I missing?

By default, VB has integer overflow checking enabled. The compiler can see that the result of (-128 and &HFF) would overflow the signed byte so it gives the compiler error: Constant expression not representable in type 'SByte'.
The code below will compile, but will generate a System.OverflowException at runtime since the result (128) is outside the range for a signed byte (with overflow checking turned on):
Public Shared Sub Main()
Dim i As Integer = -128 And &HFF
Dim b As SByte = CSByte(i)
Console.WriteLine(b)
End Sub
If you go into your project's properties, and look under Advanced Compile Options, you will see an option to "Remove integer overflow checks". If you check this value the code will compile and the result in b will be -128. Removing integer overflow checks can result in unexpected values in overflow conditions, so you will have to watch out for those.
You can also use a Byte variable and the result in b will be 128:
Public Shared Sub Main()
Dim b As Byte = CByte(-128 And &HFF)
Console.WriteLine(b)
End Sub

Related

"VBA.len" is 4 times slower than "len" (?!) [duplicate]

When I run the following macro:
Sub try()
Dim num As Integer
num = 123
MsgBox Len(num)
MsgBox VBA.Len(num)
End Sub
The first Msgbox displays 2 and the second Msgbox displays 3.
If I remove the first line which says Dim num As Integer, both MsgBoxes display 3.
Can anyone explain why?
Len and LenB are not just ordinary functions, they are keywords, and as such are found on the list of VBA keywords (although LenB is only mentioned after you click through to Len).
Mid would be another example of such keyword disguised as function, whereas e.g. Left isn't on the list at all, because that is just an ordinary function.
It has to be a keyword because one of its jobs is to perform the compile-time task of determining the storage size of a variable. E.g. with private user-defined types, an ordinary function could not do that at all:
Private Type foo
a As Long
b As String
End Type
Sub TestLens()
Dim f As foo
MsgBox Len(f) ' OK
MsgBox VBA.Len(f) ' Compile time error
End Sub
The fact that the object browser brings you to VBA.Len when you press Shift+F2 on that Len(f) is both correct and misleading.
The Len(f) here does not actually call the VBA.Len function that determines the string size, it simply cannot do that because it would require coercing a private struct into a Variant. Instead it calculates the size of foo at compile time and substitutes the result as a literal constant into the executable.
In your example the Len(num) calculates the compile-time size of variable num (which is 2) and substitutes the constant 2 into the resulting object code, whereas VBA.Len(num) packs the value of num into a Variant and passes that variant to VBA.Len where it's further converted to string "123" and the length of that is returned.
It has to do with the way that VB stores integers and how the Len() function handles arguments that are not strings.
When a datatype that is not a string is passed to the Len() function, it returns the nominal number of bytes used to store the data (VB uses 2 bytes to store an integer). See the documentation for the Len function.
The Len() function will automatically cast the variant variable (which is created by assigning a value to a variable without declaring it first) as a string. The return isn't changing because the storage allocation changes (although it does; variants require 16 bytes of storage space, minimum). Since the implicitly declared variable is actually a variant type, VB will automatically change its type based on the situation. In this case, Len() expects a string so VB makes the variable a string.
You could use Msgbox Len(Cstr(num)) to cast the integer variable as a string before passing it to the Len function if your intent is to return the number of characters in your integer value.

Short vs UShort: Hex to Decimal

Can anyone pls send me a link where the method of converting from Hexadecimal to Decimal is explained? I am not understanding why the "Short" type variable is showing a negative sign in the below example...the literal seems to be the same in both cases. I understand UShort will not take signed values but then where is the negative sign even coming from ...the literals are exactly same in both cases. Is it because I am not understanding the rules of conversion from Hexadecimal to Decimal or is it something else?
Module Module1
Sub Main()
Dim counter As Short = &H8000S 'Output: -32768
Dim flags As UShort = &H8000US 'Output: 32768
Console.WriteLine("O/P: {0} {1}", counter, flags)
Console.ReadLine()
End Sub
End Module

Widening: Change in representation

Requesting your help to understand the concept of widening better!
I came across the following statement w.r.t 'Widening Conversion' in VB.Net. From the msdn documentation on the topic I found the following: Widening conversions preserve the source value but can change its representation. This occurs if you convert from an integral type to Decimal, or from Char to String. The link to the page is found below:
https://learn.microsoft.com/en-us/dotnet/visual-basic/programming-guide/language-features/data-types/widening-and-narrowing-conversions
My Question is as follows: I wrote the following code to understand the meaning of the statement "...preserve the source value but can change its representation". But I see no difference in the output when I print the integer or the decimal. Then what does the phrase mean....what is the meaning of "...can change its representation"?
Module Module1
Sub Main()
Dim i As Integer = 5
Dim d As Decimal = i 'widening
Console.WriteLine(i)
Console.WriteLine(d)
'Both prints "5"...no difference in representation
Console.ReadLine()
End Sub
End Module
Can someone also please give an example to demonstrate how the representation changes when we convert a char value to a string?
It means the internal presentation of the number (in your case). Try to convert, say, Single to Double:
Sub Main(args As String())
Dim sng As Single = 1.23E+32
Dim dbl As Double = sng
Console.WriteLine($"Single: {sng}")
Console.WriteLine($"Double: {dbl}")
End Sub
' Output:
' Single: 1,23E+32
' Double: 1,2300000079302825E+32

Why do Len and VBA.Len return different results?

When I run the following macro:
Sub try()
Dim num As Integer
num = 123
MsgBox Len(num)
MsgBox VBA.Len(num)
End Sub
The first Msgbox displays 2 and the second Msgbox displays 3.
If I remove the first line which says Dim num As Integer, both MsgBoxes display 3.
Can anyone explain why?
Len and LenB are not just ordinary functions, they are keywords, and as such are found on the list of VBA keywords (although LenB is only mentioned after you click through to Len).
Mid would be another example of such keyword disguised as function, whereas e.g. Left isn't on the list at all, because that is just an ordinary function.
It has to be a keyword because one of its jobs is to perform the compile-time task of determining the storage size of a variable. E.g. with private user-defined types, an ordinary function could not do that at all:
Private Type foo
a As Long
b As String
End Type
Sub TestLens()
Dim f As foo
MsgBox Len(f) ' OK
MsgBox VBA.Len(f) ' Compile time error
End Sub
The fact that the object browser brings you to VBA.Len when you press Shift+F2 on that Len(f) is both correct and misleading.
The Len(f) here does not actually call the VBA.Len function that determines the string size, it simply cannot do that because it would require coercing a private struct into a Variant. Instead it calculates the size of foo at compile time and substitutes the result as a literal constant into the executable.
In your example the Len(num) calculates the compile-time size of variable num (which is 2) and substitutes the constant 2 into the resulting object code, whereas VBA.Len(num) packs the value of num into a Variant and passes that variant to VBA.Len where it's further converted to string "123" and the length of that is returned.
It has to do with the way that VB stores integers and how the Len() function handles arguments that are not strings.
When a datatype that is not a string is passed to the Len() function, it returns the nominal number of bytes used to store the data (VB uses 2 bytes to store an integer). See the documentation for the Len function.
The Len() function will automatically cast the variant variable (which is created by assigning a value to a variable without declaring it first) as a string. The return isn't changing because the storage allocation changes (although it does; variants require 16 bytes of storage space, minimum). Since the implicitly declared variable is actually a variant type, VB will automatically change its type based on the situation. In this case, Len() expects a string so VB makes the variable a string.
You could use Msgbox Len(Cstr(num)) to cast the integer variable as a string before passing it to the Len function if your intent is to return the number of characters in your integer value.

Left value of an integer

I have a value in variable, say it is dim a as integer = 145.98
I tried to take the Left(a,2)
but it returned an error instead of returning 14
I also tried left(a.Tostring,2)
but error is the same.
Please help me solve it.
Thanks
Furqan
First off, you say that you’re using an integer but the number is actually a floating-point number, not an integer.
Secondly, the action “take the left of a number” isn’t a meaningful operation. Left is a substring operation, it’s only defined on strings.
You can turn the number into a string and then extract a substring of the decimal representation. This should work. What’s the error?
Finally, some general advice:
Put Option Strict On at the very top of ever vb file, or better yet, make this option the default in your settings. Otherwise, you’ve got a veritable hullaballoo waiting to happen because VB is very … “lenient” when it comes to questionable or downright incorrect code. This option fixes this and will flag a lot more errors. For example, the compiler would (rightfully) have complained about your assignment,
Dim a As Integer = 145.98
because as I said, you’re trying to assign a floating-point number to an integer.
First of all, 145.98 is not an integer. 145 is an integer. You might want to try Double. Second, you can only take the left of a string. You were on the right track when you added ToString, but you forgot the ()s at the end.
Dim a as Integer = 145
Dim b as Double = 145.98
Then you can do this:
Left(a.ToString(), 2)
Left(b.ToString(), 2)
Try Left(a.ToString(), 2) instead.
If your "integer" is a string, try this:
Dim a As String = "145.98"
Dim b As Int32 = 0
Int32.TryParse(a.Substring(0, 2), b)
As Konrad has said with option strict this would not compile. If you don't have it on it will perform a conversion and store only the integer part. At this point you can call tostring and then performe any operation on it as a string you would like.
With option strict
Option Strict On
Module Module1
Sub Main()
Dim I As Integer = CType(142.3, Integer)
Dim s As String = I.ToString
Console.WriteLine(Left(s, 2))
End Sub
End Module
With out optiion strict
Module Module1
Sub Main()
Dim I As Integer = 142.3
Dim s As String = I
Console.WriteLine(Left(s, 2))
End Sub
End Module
As you can see from the two example option strict will attempt to perform many conversions for you but does so at the risk of unexpected results.