Typing Hard Can Trip You Up
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.)
Comments
- Anonymous
July 30, 2004
Are there reasons that you don't want to implement == and make the future less ambiguous? - Anonymous
August 02, 2004
This is trivial but I've been wanting to
ask this for a long while...
I had trouble getting hexadecimal expressions
for JScript error codes in a programmatic way.
Please consider these scripts and results.
VBS:
on error resume next
WScript.CreateObject("abc")
WScript.Echo(Err.Description)
WScript.Echo(Err.Number)
WScript.Echo(Hex(Err.Number))
on error goto 0
Result----
Automation Object named "abc" does not exist.
-2147352567
80020009
JS:
try{
WScript.CreateObject("abc");
} catch (e) {
WScript.Echo(e.description);
WScript.Echo(e.number);
WScript.Echo(e.number.toString(16));
WScript.Echo((e.number + 0x100000000).toString(16));
}
Result----
Automation Object named "abc" does not exist.
-2147352567
-7ffdfff7
80020009
----
So VBS hex() function is not equivalent to
JS Number.toString(16). I had to add 0x100000000
(which I'm not sure is exactly the right way).
Funny part is if you don't catch the exception
and let it go through, ASP or WSH runtime will
show the error codes in the usual hex format.
Do you happen to have any info on this? - Anonymous
August 02, 2004
While I was at the above I happened to find
that division by 0 in JS doesn't produce
any errors...
WScript.Echo(0/1) returns "1.#INF". - Anonymous
August 02, 2004
I already wrote an article explaining all that.
http://blogs.msdn.com/ericlippert/archive/2003/10/22/53267.aspx
And yes, 1 / 0 = infinity in JScript. Again, this is consistent with JScript's design principle: got an error? Muddle on through. - Anonymous
August 03, 2004
Oh you covered it already...my apologies.
Thanks for the info though. Wish I had read it
3 years ago. - Anonymous
August 03, 2004
You're welcome. I wish I had posted it three years ago.
:) - Anonymous
August 11, 2004
First off, I want to thank Eric for exposing the "what makes it really work" info out there for those of us who still love scripting. In my case - VBScript/ASP. I have one question: Microsoft saw fit to introduce JScript.NET, why have they forsaken us with the lack of VBScript.NET or it's equivalent? - Anonymous
August 12, 2004
We did: VB.NET is the new VBScript.
We had this conversation already.
http://weblogs.asp.net/ericlippert/archive/2004/03/11/88308.aspx
We invented VBScript because VB6 was too heavyweight to redistribute and use in web pages. But going forward, the .NET framework will be ubiquitous. (It's not yet, obviously, but it will be.) There is no additional redistrubution cost for using VB.NET.
Can we make VB.NET a better language for scripters? Sure, and I hope we do. But that's the way forward -- by improving VB.NET, not by fracturing the language yet again into ANOTHER slightly incompatible version. - Anonymous
August 12, 2004
I just recently found your site and didn't see the previous article. I understand what you're saying, although reluctantly. I've become so use to going between admin scripting and web development, without using different languages, that it seems like a huge leap to change my way of thinking into the .NET world. I feel like there are still so many things you can still do with ASP/VBScript and admin scripting with VBScript. - Anonymous
August 12, 2004
The comment has been removed - Anonymous
August 13, 2004
Do you think I should put to rest my dream of a compilable wrapper for vbscripts? I've been curious to know how Windows XP's control panels load HTAs from a dll. I see alot of potential there to code rich client apps in HTML/script, but distribute them in a secure executable fashion. I'm sure it's overkill with VB.NET looming over my shoulder. - Anonymous
August 15, 2004
The comment has been removed - Anonymous
August 16, 2004
The var types are the same because that gives you the RUN TIME variant type of the CONTENTS, not the COMPILE TIME variant type of the VARIABLE.
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 agree that it's confusing. It's confusing because it breaks the rule that behaviour should be the same whether the type was known at compile time or run time. - Anonymous
August 16, 2004
> Do you think I should put to rest my dream of a compilable wrapper for vbscripts?
The whole point of vbscript is that it is not compiled. If you want a language that compiles into DLLs or executables, use VB6 or VB.NET or C# or whatever.
> distribute them in a secure executable fashion
I'm not sure what you mean by "secure" in that sentence. Do you mean "signed"?
WSH supports code signing of vbscript files, FYI. - Anonymous
August 17, 2004
The comment has been removed - Anonymous
August 17, 2004
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. - Anonymous
August 17, 2004
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. - Anonymous
August 17, 2004
Eric,
<quote>
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.
</quote>
(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.
Thanks
Matthew - Anonymous
April 26, 2005
I've talked a few times in this blog about the semantics of the equality operators in various languages....