beercohol
beercohol

Reputation: 2587

VBS logical operators initialise empty variables?

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

Answers (4)

Kul-Tigin
Kul-Tigin

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 for Application

Visual Basic 6:

Visual Basic 6

VBScript:

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

mgr326639
mgr326639

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

Trigger
Trigger

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

Jen R
Jen R

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

Related Questions