Typing Hard Can Trip You Up

Typing Hard Can Trip You Up

  • Comments 19

Speaking of weird JScript gotchas, here's a weird VBScript gotcha that I alluded to earlier.

foo = "1"
bar = 1
If "1" = 1   Then Print "True!" Else Print "False!"
If "1" = bar Then Print "True!" Else Print "False!"
If foo = 1   Then Print "True!" Else Print "False!"
If foo = bar Then Print "True!" Else Print "False!"

This prints out "True!" for the first three and "False!" for the last.

My psychic powers tell me that you are now thinking "What the heck is up with that?" 

This weirdness is for compatibility with some similar weirdness in VB6.  VB6 violates an important principle in programming language design, namely that the semantics of an operation should be the same whether the type information about the operands was known at compile time or run time.  VB6 has different semantics for operations involving variants than for operations involving "hard typed" values when comparing strings to numbers. (Booleans count as numbers -- as I discussed earlier, they are treated as -1 and 0.) 

But that should have no impact on VBScript, right?  Because in VBScript, everything is a variant, so there should be no such issue.  Well, not exactly.  All variables are treated as though they were declared as variant, sure.  And internally, all data is stored in variants.  But as far as comparison operations go, VBScript follows VB6's lead and treats literals as hard-typed values.

The relevant comparison rules in VB6/VBScript go like this:

  • Hard string ~ hard number: convert string to number, compare numbers
  • Hard string ~ soft number: convert number to string, compare strings
  • Soft string ~ hard number: convert string to number, compare numbers
  • Soft string ~ soft number: any string is greater than any number

Though they violate the principle that semantics should be consistent regardless of when the type information is deduced, the middle two rules do make some sense -- the "soft" side is converted into the type of the "hard" side for the comparison.  The first and last rules are both arbitrary, and either is defensible.  What I don't understand is why the first and last aren't consistent with each other.  That just seems egregiously wrong to me.  Someone who knows more about the history of VB than I do will have to chime in here!  This has always irked me about VB6/VBScript, but there's nothing I can do about it now.  (And of course these rules also violate the transitive property of the equality operator, which is irksome in itself.)

It gets even weirder when you consider Boolean/string comparisons:

bobble = "True"
robble = True
If "True" = True   Then Print "True!" Else Print "False!"
If "True" = robble Then Print "True!" Else Print "False!"
If bobble = True   Then Print "True!" Else Print "False!"
If bobble = robble Then Print "True!" Else Print "False!"

That produces "True!" for the first two, "False!" for the last two.  Again, what the hey?   Why is this different from the case above?

That's a bug.  VB6 does what you'd expect, and is consistent with the integer behaviour.  We forgot to emit code that marks hard-typed Booleans as hard-typed.  Therefore VBScript uses the rules for soft typing regardless of whether the Boolean is a literal or not.  This is yet another on the long list of small, unintended deviations from the VB6 subset.

Unfortunately, by the time we discovered the bug it was too late -- the bug had shipped to customers.  We considered fixing it, but realized that it was more important to not take the chance of breaking existing scripts than to fix this rather unimportant incompatibility with VB6.  (That wasn't the only time we passed on fixing a bug because the fix would break backwards compatibility.  But that's another story.)

  • Clearly VBScript is compiled, but it is not compiled into an executable, which is what the poster was asking for.

    There are a number of non-compatibilities with VB6, mostly due to mistakes. Most of them are documented in my blog at one point or another, but it might be interesting to get all of them in one place at some time.
  • I was thinking in terms of the way you have the *full* security model of executables when running an HTA. I can program a nice app that looks almost as good as an executable, but has a .hta extension. One problem is that the source is still fully viewable. What if you I could make a application using html and script (HTA) and then package it into an executable that when run - loads the HTA into memory and executes it from there? This would allow for the flexibility of scripting, with the speed and security (of source code) that a normal Win32 has.
  • Eric,

    And then the difference is because in the one case you're comparing a hard string to a hard bool, in the other you're comparing a soft string to a soft bool.

    (I assume you mean hard bool instead of soft bool at the end).

    That does 'explain' the problem (or at least reduce my confusion!).

    http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vbenlr98/html/vagrpcomparison.asp doesn't seem to help (thinking back, it probably initiated by confusion) since it states:

    * One expression is a numeric data type and the other is a string Variant that can't be converted to a number -> A Type Mismatch error occurs. This appears to cover the MsgBox x = True case (or Msgbox x = 1, or whatever), but that isn't what happens.

  • I've talked a few times in this blog about the semantics of the equality operators in various languages....
Page 2 of 2 (19 items) 12