2

I am working with a legacy code base written in VB and have run into a conditional operator that I don't understand and cannot figure out what to search for to resolve it.

What I am dealing with is the following code and the variables that result as true. The specific parts that I do not understand are (1) the relationship between the first X and the first parens (-2 and (2) the role of X < 2

  • If X is a value below -2 it evaluates as false.
  • If X is a value above 2 it evaluates as true.
  • If Y is below 5 it evaluates to true as expected.

X = 3
Y = 10

If X > (-2 And X < 2) Or Y < 5 Then
    'True
Else
    'False
End If
chrisphilton
  • 459
  • 3
  • 7
  • Not sure exactly what's going on (hence just a comment), but I'd bet the trick here relies on the fact that `And` is a _bitwise_ operator, rather than a straight conditional operator. Given any excuse I'd re-write it to be easier to understand how it follows the spec. The existing code might be faster than something that's easier to understand, but I doubt this expression is driving your application's performance in a meaningful way. – Joel Coehoorn Sep 20 '17 at 19:48
  • @JoelCoehoorn - I definitely agree with re-writing it as well is it not being crucial to performance. Unfortunately, I don't know the original intention of the logical operators in this particular part of the code base, hence attempting to figure out what it could be trying to solve for :/ – chrisphilton Sep 20 '17 at 19:53
  • 2
    You are comparing an Integer to a Boolean. And a Boolean to an Integer. That gives the compiler a headache that it needs to sort out. With perhaps the somewhat surprising result that True equals -1. Which was a fairly brilliant move that ensures that the And and Or operators can work both as bitwise and logical operators. Really rather best to not give the compiler a headache and it won't give you one either. – Hans Passant Sep 20 '17 at 19:53
  • 1
    **Can you make sure that the output is *indeed* the desired one?** I don't have any proof to back this up, but I have a feeling, *just a feeling* that there's a typo in this code, where the original intention was to simply write `If (X > -2 And X <2) Or Y < 5`, and no bitwise operations were meant to be involved, hence this can be optimized by replacing `And` & `Or` with `AndAlso` & `OrElse`. Perhaps we can find an evidence to prove *or refute* this if you can provide more context. – 41686d6564 stands w. Palestine Sep 20 '17 at 22:04

2 Answers2

5

I'm gonna leave off the Or Y < 5 part of the expression for this post as uninteresting, and limit myself to the X > (-2 And X < 2) side of the expression.

I haven't done much VB over the last several years, so I started out with some digging into Operator Precedence rules in VB, to be sure I have things right. I found definitive info on VBA and VB.Net, and some MSDN stuff that might have been VB6 but could also have been the 2013 version of VB.Net. All of them, though, gave the < and > comparison operators higher precedence over the And operator, regardless of whether you see And as logical or bitwise.

With that info, and also knowing that we must look inside parentheses first, I'm now confident the very first part of the expression to be evaluated is X < 2 (rather than -2 And X). Further, we know this will produce a Boolean result, and this Boolean result must be then converted to an Integer to do a bitwise (not logical) And with -2. That result (I'll call it n), which is still an Integer, can at last be compared to see if X > n, which will yield the final result of the expression as a Boolean.

I did some more digging and found this Stack Overflow answer about converting VB Booleans to Integers. While not definitive documentation, I was once privileged to meet the author (Hi @JaredPar) and know he worked on the VB compiler team at Microsoft, so he should know what he's talking about. It indicates that VB Boolean True has the surprising value of -1 as an integer! False becomes the more-normal 0.

At this point we need to talk about the binary representation of negative numbers. Using this reference as a guide (I do vaguely remember learning about this in college, but it's not the kind of thing I need every day), I'm going to provide a conversion table for integers from -3 to +3 in an imaginary integer size of only 4 bits (short version: invert the bit pattern and add one to get the negative representation):

-3   1101
-2   1110
-1   1111 --this helps explain **why** -1 was used for True
 0   0000
 1   0001
 2   0010
 3   0010

Stepping back, let's now consider the original -2 And X < 2 parenthetical and look at the results from the True (-1) and False (0) possible outcomes for X < 2 after a bitwise And with -2:

-2 (1110) And True  (1111) = 1110 = -2
-2 (1110) And False (0000) = 0000 =  0

Really the whole point here from using the -1 bit pattern is anything And True produces that same thing you started with, whereas anything And False produces all zeros.

So if X < 2 you get True, which results in -2; otherwise you end up with 0. It's interesting to note here that if our language used positive one for True, you'd end up with the same 0000 value doing a bitwise And with -2 that you get from False (1110 And 0001).

Now we know enough to look at some values for X and determine the result of the entire original expression. Any positive integer is greater than both -2 and 0, so the expression should result in True. Zero and -1 are similar: they are less than two, and so will be compared again only as greater than -2 and thus always result in True. Negative two, though, and anything below, should be False.

Unfortunately, this means you could simplify the entire expression down to X > -2. Either I'm wrong about operator precedence, my reference for negative integer bit patterns is wrong, you're using a version of VB that converts True to something other than -1, or this code is just way over-complicated from the get-go.

Joel Coehoorn
  • 399,467
  • 113
  • 570
  • 794
1

I believe the sequence is as follows:

r = -2 and X 'outputs X with the least significant bit set to 0 (meaning the first lesser even number)

r = (r < 2) 'outputs -1 or 0

r = (X > r) 'outputs -1 or 0

r = r Or (Y < 5)

Use AndAlso and OrElse.