Reputation: 2587
Consider the following bit of VBS:
dim msg, myVar, myVar2
msg = "myVar = " & myVar
msg = msg & vbcrlf & "myVar = empty: " & isempty(myVar)
msg = msg & vbcrlf & "TypeName(myVar) = " & TypeName(myVar)
msgbox msg, , "BEFORE"
if not myVar then myVar2 = true
msg = "myVar = " & myVar
msg = msg & vbcrlf & "myVar = empty: " & isempty(myVar)
msg = msg & vbcrlf & "TypeName(myVar) = " & TypeName(myVar)
msgbox msg, , "AFTER"
I would expect the output from "BEFORE" and "AFTER" to be the same... all we're doing is making a comparison to an uninitialised (empty) variant right?
However - it seems like the "if not" actually initialises it to a (long)zero! I've been coding in VBS (ASP) for donkey's years, and this is a new one on me!
A few things to note:
It seems like a potential trap for the unwary... Can anyone explain this behaviour?
Upvotes: 11
Views: 1549
Reputation: 16950
I couldn't find anything official about this issue. After doing some test, I decided that this is a bug or an un-documented effect. This behaviour does not apply on other similar platforms like VBA and VB6.
Visual Basic for Application:
Visual Basic 6:
VBScript:
As a workaround, passing expressions by value works.
If Not (exp) Then
'or
If Not CBool(exp) Then
ByRef and ByVal Parameters
CBool Function
Upvotes: 6
Reputation: 912
If you change that statement in the middle to
if not (myVar) then myVar2 = true 'with parenthesis around myVar
then you will not witness the same behavior. BEFORE and AFTER are the same now.
That's because apparently the parenthesis force the Not operator to only perform a logical test and will skip the side effect of Not.
On https://msdn.microsoft.com/en-us/subscriptions/9cy86sfb%28v=vs.84%29.aspx you will find the following about Not
In addition, the Not operator inverts the bit values of any variable and
sets the corresponding bit in result according to the following table:
+-------------------+---------------+
| Bit in expression | Bit in result |
+-------------------+---------------+
| 0 | 1 |
| 1 | 0 |
+-------------------+---------------+
For example
Msgbox Not 2 ' is -3
Msgbox Not -3 ' is 2
That makes sense if you consider that internally the values are stored as signed bytes/words.
000 -4
001 -3 --> 001 inverted is 110
010 -2
011 -1
100 0
101 1
110 2 --> 110 inverted is 001
111 3
Let's convert Empty to Long with
x = CLng(myVar)
You will find that the value of x is 0.
If you use
if not myVar then myVar2 = true
then the result of not myVar will be evaluated (and the resulting value of -1 will subsequently be thrown away). But the calculation takes place anyhow and for this it is necessary to convert Empty to a long first.
Upvotes: 5
Reputation: 691
These are the rules from VBA https://msdn.microsoft.com/en-us/library/ee177324.aspx?f=255&MSPPError=-2147217396
The point is that variables (though not objects) always have a usuable value (objects do have a value of nothing).
5.5.1.2.2 Let-coercion to and from Boolean
When not stored as a Boolean value, False is represented by 0, and True is represented by nonzero values, usually -1.
The semantics of Boolean Let-coercion depend on the source’s value type and the destination’s declared type:
Source Value Type Destination Declared Type Semantics
Boolean Boolean The result is a copy of the source value.
Boolean Any numeric type except Byte If the source value is False, the result is 0. Otherwise, the result is -1.
Boolean Byte If the source value is False, the result is 0. Otherwise, the result is 255.
Any numeric type Boolean If the source value is 0, the result is False. Otherwise, the result is True
5.5.1.2.11 Let-coercion from Empty
The semantics of Empty Let-coercion depend on the destination’s declared type:
Source Value Type Destination Declared Type Semantics
Empty Any numeric type The result is 0.
Empty Boolean The result is False.
Empty Date The result is 12/30/1899 00:00:00.
Empty String The result is a 0-length string.
Empty String * length The result is a string containing length spaces.
Empty Any class or Object Runtime error 424 (Object required) is raised.
Empty Any other type except Variant Runtime error 13 (Type mismatch) is raised.
Your variable is coerced as a string when you first messagebox it.
Then it is coerced as false in line above.
5.6.9.5 Relational Operators Relational operators are simple data operators that perform comparisons between their operands.
relational-operator = equality-operator / inequality-operator / less-than-operator / greaterthan-operator / less-than-equal-operator / greater-than-equal-operator
Static semantics:
Relational operators are statically resolved as simple data operators.
A relational operator is invalid if the declared type of any operand is an array or UDT.
A relational operator has the following declared type, based on the declared type of its operands:
Left Operand Declared Type Right Operand Declared Type Operator Declared Type
Any type except an array, UDT or Variant Any type except an array, UDT or Variant Boolean Any type except an array or UDT Variant
Variant Any type except an array or UDT Variant
Runtime semantics:
Relational operators are first evaluated as simple data operators.
If the value type of any operand is an array or UDT, runtime error 13 (Type mismatch) is raised.
Before evaluating the relational operator, its non-Null operands undergo Let-coercion to the operator’s effective value type.
The effective value type is determined as follows, based on the value types of the operands:
5.6.9.5.1 = Operator
The = operator performs a value equality comparison on its operands. equality-operator = expression "=" expression
Runtime semantics:
If the operands are considered equal, True is returned. Otherwise, False is returned.
Upvotes: 3
Reputation: 1535
https://technet.microsoft.com/en-us/library/ee198865.aspx
So, if you create a variable without initializing it, the variable will take on one of these default values: If you use the variable as a string, the initial value will be Empty. If you use the variable as a number, the initial value will be 0.
I would think that since you are doing a Boolean check, you are essentially using myVar as a number, and your statement is read like:
if not 0 then myVar2 = true
'same as: if not FALSE then myVar2 = true
And so myVar is initialized to 0
Upvotes: 4