<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://blogs.msdn.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Fabulous Adventures In Coding : VBScript</title><link>http://blogs.msdn.com/ericlippert/archive/tags/VBScript/default.aspx</link><description>Tags: VBScript</description><dc:language>en-US</dc:language><generator>CommunityServer 2.1 SP1 (Build: 61025.2)</generator><item><title>As Timeless As Infinity</title><link>http://blogs.msdn.com/ericlippert/archive/2009/10/15/as-timeless-as-infinity.aspx</link><pubDate>Thu, 15 Oct 2009 13:25:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9904452</guid><dc:creator>Eric Lippert</dc:creator><slash:comments>32</slash:comments><comments>http://blogs.msdn.com/ericlippert/comments/9904452.aspx</comments><wfw:commentRss>http://blogs.msdn.com/ericlippert/commentrss.aspx?PostID=9904452</wfw:commentRss><description>&lt;DIV class=mine&gt;
&lt;P&gt;&lt;STRONG&gt;User:&lt;/STRONG&gt; Recently I found out about a peculiar behaviour concerning division by zero in floating point numbers in C#. It does not throw an exception, as with integer division,&amp;nbsp;but rather returns an "infinity". Why is that?&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Eric:&lt;/STRONG&gt; As I've often said, "why" questions are difficult for me&amp;nbsp;to answer. My first attempt at an answer to a "why" question is usually "because that's what the specification says to do"; this time is no different. The C# specification says to do that in section 4.1.6. But we're only doing that because that's what&amp;nbsp;the IEEE standard for floating point arithmetic says to do. We wish to be compliant with the established industry standard. See &lt;A href="http://en.wikipedia.org/wiki/IEEE_754-1985" mce_href="http://en.wikipedia.org/wiki/IEEE_754-1985"&gt;IEEE standard 754-1985&lt;/A&gt; for details. Most floating point&amp;nbsp;arithmetic&amp;nbsp;is done in hardware these days, and most hardware is compliant with this specification.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;User:&lt;/STRONG&gt;&amp;nbsp;It seems to me that division by zero is a bug no matter how you look at it!&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Eric:&lt;/STRONG&gt; Well, since clearly that is not how the members of the IEEE standardization committee looked at it in 1985, your statement that it must be a bug "no matter how you look at it" must be incorrect. Some industry experts do not look at it that way.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;User:&lt;/STRONG&gt;&amp;nbsp;Good point. What motivated this design decision?&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Eric:&lt;/STRONG&gt; I wasn't there; I was busy playing&amp;nbsp;Jumpman on my Commodore 64 at the time. But my educated guess is that &lt;STRONG&gt;it is desirable for all possible operations on all floats to produce a well-defined float result&lt;/STRONG&gt;. Mathematicians would call this a "closure" property; that is, the set of floating point numbers is "closed" over all operations.&lt;/P&gt;
&lt;P&gt;Positive infinity seems like a reasonable choice for dividing a positive number by zero. It seems plausible because of course the limit of 1 / x as x goes to zero (from above)&amp;nbsp;is "positive infinity", so why shouldn't 1/0 be the number "positive infinity"?&lt;/P&gt;
&lt;P&gt;Now, speaking &lt;EM&gt;as a mathematician&lt;/EM&gt;, I find that argument specious. A thing&amp;nbsp;and its limit need not have any particular property in common; it is fallacious to reason that just because, say, a sequence has a particular limit that a fact about the limit is also a fact about the sequence. Mathematically, "positive infinity" (in the sense of a limit of a real-valued function; let's leave transfinite ordinals, hyperbolic geometry, and all of that&amp;nbsp;other stuff out of this discussion)&amp;nbsp;is not a number at all and should not be treated as one; rather, it's a terse way of saying "the limit does not exist because the sequence diverges upwards". &lt;/P&gt;
&lt;P&gt;When we divide by zero, essentially what we are saying is "solve the equation x * 0 = 1"; the solution to that equation is not "positive infinity", it is "I cannot because there is no solution to that equation". It's just the same as asking to solve the equation "x + 1 = x" -- saying "x is positive infinity" is not a solution; there is no solution.&lt;/P&gt;
&lt;P&gt;But speaking &lt;EM&gt;as a practical engineer&lt;/EM&gt; who uses floating point numbers to do an imprecise approximation of ideal arithmetic, this seems like a perfectly reasonable choice. &lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;User:&lt;/STRONG&gt;&amp;nbsp;But surely it is impossible for the hardware to represent "infinity".&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Eric:&lt;/STRONG&gt; It certainly is possible. You've got 32 bits in a single-precision float; that's over four billion possible floats. All bit patterns of the form &lt;/P&gt;
&lt;P&gt;?11111111??????????????????????? &lt;/P&gt;
&lt;P&gt;are reserved for "not-a-number" values. That's over sixteen million possible NaN combinations. Two of those sixteen million NaN bit patterns are reserved to mean positive and negative infinity. Positive infinity is the bit pattern 01111111100000000000000000000000 and negative infinity is 11111111100000000000000000000000. &lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;User:&lt;/STRONG&gt;&amp;nbsp;Do all languages and applications use this convention of division-by-zero-becomes-infinity?&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Eric: &lt;/STRONG&gt;No.&amp;nbsp;For example, C#&amp;nbsp;and JScript do but&amp;nbsp;VBScript does not. VBScript gives an error if you do that.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;User:&lt;/STRONG&gt;&amp;nbsp;Then how do language implementors get the desired behaviour for each language if these semantics are implemented by the hardware?&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Eric: &lt;/STRONG&gt;There are two basic techniques. First, many chips which implement this standard allow&amp;nbsp;the programmer&amp;nbsp;to make float division by zero an exception rather than an infinity. On the 80x87 chip, for example, you can use bit two of the precision control register to determine whether division by zero returns an infinity or&amp;nbsp;throws a hardware exception. &lt;/P&gt;
&lt;P&gt;Second, if you don't want it to be a hardware exception but do want it to be a software exception, then you can check bit two of the status register after each division;&amp;nbsp;it records whether there was&amp;nbsp;a recent divide-by-zero event. &lt;/P&gt;
&lt;P&gt;The latter strategy is used by VBScript; after we perform a division operation we check to see whether the status register recorded a divide-by-zero operation; if it did, then the VBScript runtime creates a divide-by-zero error and the usual VBScript error management&amp;nbsp;process takes over, same as any other error.&lt;/P&gt;
&lt;P&gt;Similar bits exist for other operations that seem like they might be better treated as exceptions, like numeric overflow.&lt;/P&gt;
&lt;P&gt;The existence of the "hardware exception" bits creates problems for the modern&amp;nbsp;language implementor, because we are now often in a world where code written in multiple languages from multiple vendors is running in the same process. Control bits on hardware are the ultimate "global state", and we all know how irksome it is to have global, public state that random code can stomp on. &lt;/P&gt;
&lt;P&gt;For example: I might be misremembering some details, but I seem to recall that Delphi-authored controls set the "overflows cause exceptions" bit. That is, the Delphi implementors did not use the VBScript strategy of "try it, allow it to succeed, and check to see whether the&amp;nbsp;overflow bit was set in the status register". Rather, they used the "make the hardware throw an exception and then catch the exception" strategy. This is deeply unfortunate.&amp;nbsp;When a VBScript script&amp;nbsp;calls a Delphi-authored control, the control flips the bit to force exceptions but it never "unflips" it. If, later on in the script, the VBScript program does an overflow, then we get an unhandled hardware exception because the bit is still set, even though the Delphi control might be long gone! I fixed that by saving away the state of the control register before calling into a component and restoring it when control returns. That's not ideal, but there's not much else we can do.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;User:&lt;/STRONG&gt;&amp;nbsp;Very enlightening! I will be sure to pass this information along to my coworkers. I would be delighted to see a blog post on this.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Eric: &lt;/STRONG&gt;And here you go!&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;&lt;/DIV&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9904452" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/ericlippert/archive/tags/VBScript/default.aspx">VBScript</category><category domain="http://blogs.msdn.com/ericlippert/archive/tags/C_2300_/default.aspx">C#</category><category domain="http://blogs.msdn.com/ericlippert/archive/tags/Floating+Point+Arithmetic/default.aspx">Floating Point Arithmetic</category><category domain="http://blogs.msdn.com/ericlippert/archive/tags/Dialogue/default.aspx">Dialogue</category><category domain="http://blogs.msdn.com/ericlippert/archive/tags/Language+Design/default.aspx">Language Design</category><category domain="http://blogs.msdn.com/ericlippert/archive/tags/exception+handling/default.aspx">exception handling</category><category domain="http://blogs.msdn.com/ericlippert/archive/tags/Delphi/default.aspx">Delphi</category></item><item><title>Bug Psychology</title><link>http://blogs.msdn.com/ericlippert/archive/2009/06/01/bug-psychology.aspx</link><pubDate>Mon, 01 Jun 2009 16:48:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9659959</guid><dc:creator>Eric Lippert</dc:creator><slash:comments>28</slash:comments><comments>http://blogs.msdn.com/ericlippert/comments/9659959.aspx</comments><wfw:commentRss>http://blogs.msdn.com/ericlippert/commentrss.aspx?PostID=9659959</wfw:commentRss><description>&lt;DIV class=mine&gt;
&lt;P&gt;Fixing bugs is hard.&lt;/P&gt;
&lt;P&gt;For the purposes of this posting, I’m talking about those really “crisp” bugs -- those flaws which are entirely due to a failure on the developer’s part to correctly implement some mechanistic calculation or ensure some postcondition is met. I’m not talking about oops, &lt;EM&gt;we just found out that the product name sounds like a rude word in Urdu&lt;/EM&gt;, or &lt;EM&gt;the specification wasn’t quite right so we changed it&lt;/EM&gt; or the code wasn’t &lt;EM&gt;adequately robust in the face of a buggy caller&lt;/EM&gt;. I mean those bugs where you were asked to compute some value and you just plain get the result &lt;EM&gt;wrong&lt;/EM&gt; for some valid inputs.&lt;/P&gt;
&lt;P&gt;Let me give you an example.&lt;/P&gt;
&lt;P&gt;The first bug I ever fixed at Microsoft as a full-time employee was one of those. To understand the context of the bug, &lt;A href="http://blogs.msdn.com/ericlippert/archive/2003/09/16/53013.aspx" mce_href="http://blogs.msdn.com/ericlippert/archive/2003/09/16/53013.aspx"&gt;start by reading this post from the early days of FAIC, and then come back.&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;Welcome back, I hope you enjoyed that little trip down memory lane as much as I did.&lt;/P&gt;
&lt;P&gt;Now that you understand how a VT_DATE is stored, that explains this bizarre behaviour in VBScript:&lt;/P&gt;&lt;SPAN class=code&gt;
&lt;P&gt;print DateDiff("h", #12/31/1899 18:00#, #12/30/1899 6:00#) / 24&lt;BR&gt;print DateDiff("h", #12/31/1899 18:00#, #12/29/1899 6:00#) / 24&lt;/P&gt;&lt;/SPAN&gt;
&lt;P&gt;This prints –1.5 and –2.5, as you’d expect. There’s a day and a half between 6 AM December 30th and 6 PM December 31st, and two and a half days between the other two dates. This is perfectly understandable. But if you just subtract the dates:&lt;/P&gt;&lt;SPAN class=code&gt;
&lt;P&gt;print #12/31/1899 18:00# - #12/30/1899 6:00#&lt;BR&gt;print #12/31/1899 18:00# - #12/29/1899 6:00# &lt;/SPAN&gt;
&lt;P&gt;You get 1.5 and 3, not 1.5 and 2.5. Because of the bizarre date format that VT_DATE chooses, when you convert dates to numbers, you cannot safely subtract them if they straddle the magic zero date. That’s why you need the helpful “DateDiff”, “DateAdd” and so on, methods. &lt;/P&gt;
&lt;P&gt;The bug I was assigned was that testing had discovered a particular pair of dates which DateDiff was not subtracting correctly. I took a look at the source code for one of the helper methods that DateDiff used to do one of the computations it needed along the way. To my fresh-out-of-college eyes it looked something like this:&lt;/P&gt;&lt;SPAN class=code&gt;
&lt;P&gt;if (frob(x) &amp;gt; 0 &amp;amp;&amp;amp; blarg(y)) return x – y;&lt;BR&gt;else if (frob(x) &amp;lt; blarg(y) &amp;amp;&amp;amp; blah_blah(x) &amp;gt; 0 || blah_de_blah_blah_blah(x,y)) return frob(x) – x + y + 1;&lt;BR&gt;else if…&lt;/P&gt;&lt;/SPAN&gt;
&lt;P&gt;There were seven such cases.&lt;/P&gt;
&lt;P&gt;My urge was to dive right in and add an eighth special case that fixed the bug. But my ability to get it right in the face of all this complexity concerned me. It seemed like this was an awfully complicated function already for what it was trying to do. &lt;/P&gt;
&lt;P&gt;I researched the history of the code a bit and discovered that in fact variations on this bug had been entered… seven times. Each special case in the code corresponded to a particular bug that had been “fixed”, a term I use guardedly in this case. A great many of those “fixes” had actually introduced new bugs, regressing existing correct behaviour, which then in turn were “fixed” by adding special cases on top of the broken special cases that had been added to “fix” previous bugs.&lt;/P&gt;
&lt;P&gt;I decided that this coding horror would end here. I deleted all the code (all seven lines of it! I was bold!) and started over.&lt;/P&gt;
&lt;P&gt;Deep breath. &lt;/P&gt;
&lt;P&gt;Spec the code requirements first. Then design the code to meet the spec.&amp;nbsp;Then write the code to the design.&lt;/P&gt;
&lt;P&gt;Spec:&lt;/P&gt;
&lt;P&gt;* Input: two doubles representing dates in VT_DATE format.&lt;BR&gt;* VT_DATE format: signed integer portion of double is number of days since 12/30/1899, unsigned fractional part is portion of day gone by.&lt;BR&gt;* For example: –1.75 = 12/29/1899, 6 PM.&lt;BR&gt;* Output: double containing number of days, possibly fractional, between two dates.&amp;nbsp; Differences due to daylight savings time, and so on, to be ignored.&lt;BR&gt;&lt;BR&gt;Design strategy:&lt;/P&gt;
&lt;P&gt;* Problem: Some doubles cannot simply be subtracted because negative dates are not absolute offsets from epoch time&lt;BR&gt;* Therefore, convert all dates to a more sensible date format which can be simply subtracted.&lt;/P&gt;
&lt;P&gt;Code:&lt;/P&gt;&lt;SPAN class=code&gt;
&lt;P&gt;double DateDiffHelper(double vtdate1, double vtdate2)&lt;BR&gt;{&lt;BR&gt;&amp;nbsp; return SensibleDate(vtdate2) – SensibleDate(vtdate1);&lt;BR&gt;}&lt;BR&gt;double SensibleDate(double vtdate)&lt;BR&gt;{&lt;BR&gt;&amp;nbsp; // negative dates like –2.75 mean “go back two days, then forward .75 days”:&lt;BR&gt;&amp;nbsp; // Transform that into –1.25, meaning “go back 1.25 days”.&lt;BR&gt;&amp;nbsp; return DatePart(vtdate) + TimePart(vtdate);&lt;BR&gt;}&lt;/P&gt;&lt;/SPAN&gt;
&lt;P&gt;I already had helper methods DatePart and TimePart, so I was done. The new code was shorter, far more readable, generated smaller, faster machine code and most important, was &lt;STRONG&gt;clearly correct&lt;/STRONG&gt;. No special cases; no bugs. &lt;/P&gt;
&lt;P&gt;It’s not that my coworkers were dummies. Far from it. These were smart people. But computer geek psychology is such that it is very easy to narrow-focus on the immediately wrong thing, and try to tweak it until it does the right thing. &lt;/P&gt;
&lt;P&gt;When faced with these sorts of “crisp” bugs, I try to restrain myself from diving right in. Rather, I try to psychoanalyze the person – who is, of course, usually my past self – who caused the bug. I ask myself “how was the person who wrote the buggy code fooled into thinking it was correct?” Did they not have a clear specification of what the method was supposed to do? Was it misleading? Did they have a clear plan for how to proceed? If so, where did it go wrong? &lt;/P&gt;
&lt;P&gt;If there never was either a spec or a plan, then for all you know the whole thing might only be working by sheer accident. There could be any number of design flaws in the thing that just haven’t come to light yet. Editing such a beast means adding unknown to unknown. which seldom leads to good results. Sometimes coming up with a new spec, a new plan and scrapping an existing bug farm is the best way to proceed.&lt;/P&gt;
&lt;P&gt;For many years after that, I would ask how to implement DateDiffHelper as my technical question for fresh-out-of-college candidates that I was interviewing for the scripting dev team. I reasoned that if that was the sort of problem I was given on my first day in the office, then maybe that would be a reasonable question to ask a candidate. &lt;/P&gt;
&lt;P&gt;When you ask the same question over and over again, you really get to see the massive difference in aptitude between candidates. I had some candidates who just picked up a marker, wrote a solution straight out on the board, wrote down the test cases they’d use to verify it, mentally ran a few of the tests in their head, and then we’d have another half hour to chat about the weather. And I had some candidates who tried earnestly to write the version using special cases, despite my specifically telling them “you might consider transforming this bad format into something more pleasant to work with”, after they got stuck on the third special case. I’d point out a bug and immediately they’d write down code for another special case, rather than stopping to think about the fact that they’d just written buggy code three times already and told me it was correct three times.&lt;/P&gt;&lt;/DIV&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9659959" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/ericlippert/archive/tags/VBScript/default.aspx">VBScript</category><category domain="http://blogs.msdn.com/ericlippert/archive/tags/Scripting/default.aspx">Scripting</category><category domain="http://blogs.msdn.com/ericlippert/archive/tags/Rants/default.aspx">Rants</category><category domain="http://blogs.msdn.com/ericlippert/archive/tags/Interviewing/default.aspx">Interviewing</category></item><item><title>Reading Code Over the Telephone</title><link>http://blogs.msdn.com/ericlippert/archive/2008/05/16/reading-code-over-the-telephone.aspx</link><pubDate>Fri, 16 May 2008 17:00:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8495414</guid><dc:creator>Eric Lippert</dc:creator><slash:comments>25</slash:comments><comments>http://blogs.msdn.com/ericlippert/comments/8495414.aspx</comments><wfw:commentRss>http://blogs.msdn.com/ericlippert/commentrss.aspx?PostID=8495414</wfw:commentRss><description>&lt;DIV class=mine&gt;
&lt;P&gt;In my youth I once attended a lecture given by Brian Kernighan on the subject of code quality, which was very influential on my attitudes towards writing legible code. One of the things that Kernighan recommended was to endeavour write code that was so clear that it could be easily read over the phone and understood. Most people find code much easier to comprehend when read than when heard; if you can make it clear enough to be understood when heard, it's probably pretty clear code.&lt;/P&gt;
&lt;P&gt;I was reminded of this when I got the following question from&amp;nbsp;a colleague by email:&lt;/P&gt;&lt;SPAN class=code&gt;
&lt;P&gt;Subject: Stupid C# 3.0 lambda expression question&lt;/P&gt;
&lt;P&gt;How does one read the =&amp;gt; operator? &lt;/P&gt;&lt;/SPAN&gt;
&lt;P&gt;First off, I told my colleague that &lt;STRONG&gt;there are no stupid &lt;EM&gt;questions&lt;/EM&gt;, only stupid &lt;EM&gt;people&lt;/EM&gt;&lt;/STRONG&gt;. No stupid people work here, so don't stress about it. This is a perfectly sensible question.&lt;/P&gt;
&lt;P&gt;As far as I know, we do not have an "official" line on how to read this operator over the phone. In the absense of any other context, I personally would say &lt;SPAN class=code&gt;c=&amp;gt;c+1&lt;/SPAN&gt; as "see &lt;STRONG&gt;goes to&lt;/STRONG&gt; see plus one". Some variations that I've heard:&lt;/P&gt;
&lt;P&gt;For a projection, &lt;SPAN class=code&gt;(Customer c)=&amp;gt;c.Name&lt;/SPAN&gt;: "customer see &lt;STRONG&gt;becomes&lt;/STRONG&gt; see dot name"&lt;/P&gt;
&lt;P&gt;For a predicate, &lt;SPAN class=code&gt;(Customer c)=&amp;gt;c.Age &amp;gt; 21&lt;/SPAN&gt;: "customer see &lt;STRONG&gt;such that&lt;/STRONG&gt; see dot age is greater than twenty-one"&lt;/P&gt;
&lt;P&gt;An unfortunate conflation is that the =&amp;gt; operator looks a lot like ⇒, the "implies" operator in mathematics. Since =&amp;gt; does not have the same semantics as ⇒, it is probably a bad idea to read =&amp;gt; as "implies". (x⇒y&amp;nbsp;would have&amp;nbsp;the semantics of &lt;SPAN class=code&gt;!x|y&lt;/SPAN&gt; in C#.)&lt;/P&gt;
&lt;P&gt;Incidentally, it is a little known fact that VB6 and VBScript implemented the ⇒ operator with the &lt;SPAN class=code&gt;Imp&lt;/SPAN&gt; keyword and the ⇔ operator with the &lt;SPAN class=code&gt;Eqv&lt;/SPAN&gt; keyword. They disappeared in VB.NET. Where did they go? It is a mystery!&lt;/P&gt;&lt;/DIV&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=8495414" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/ericlippert/archive/tags/VBScript/default.aspx">VBScript</category><category domain="http://blogs.msdn.com/ericlippert/archive/tags/C_2300_/default.aspx">C#</category><category domain="http://blogs.msdn.com/ericlippert/archive/tags/Lambda+Expressions/default.aspx">Lambda Expressions</category><category domain="http://blogs.msdn.com/ericlippert/archive/tags/Code+Quality/default.aspx">Code Quality</category></item><item><title>Do Not Call IsBadFooPtr, Indeed</title><link>http://blogs.msdn.com/ericlippert/archive/2006/09/27/774117.aspx</link><pubDate>Wed, 27 Sep 2006 21:16:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:774117</guid><dc:creator>Eric Lippert</dc:creator><slash:comments>11</slash:comments><comments>http://blogs.msdn.com/ericlippert/comments/774117.aspx</comments><wfw:commentRss>http://blogs.msdn.com/ericlippert/commentrss.aspx?PostID=774117</wfw:commentRss><description>&lt;DIV class=mine&gt;
&lt;P&gt;Here’s a story that I said &lt;A href="http://blogs.msdn.com/ericlippert/archive/2004/03/31/105329.aspx"&gt;a long time ago that I was going to tell you all&lt;/A&gt;, and then promptly forgot about it. &lt;A href="http://blogs.msdn.com/oldnewthing/archive/2006/09/27/773741.aspx"&gt;Raymond Chen’s blog entry today&lt;/A&gt; reminded me of it, because this is the story of how I found out the hard way that &lt;SPAN class=code&gt;IsBadFooPtr&lt;/SPAN&gt; is bad, bad, bad. Those of you who have been following releases of the script engines incredibly carefully may remember this story, but hopefully we caused and then fixed the problem sufficiently quickly that the vast majority of customers never noticed. &lt;/P&gt;
&lt;P&gt;But I’m getting ahead of myself. &lt;/P&gt;
&lt;P&gt;One of the most basic and important rules of COM programming is that you never, ever, &lt;B&gt;EVER&lt;/B&gt; change an interface without changing its &lt;SPAN class=code&gt;GUID&lt;/SPAN&gt;. Or, to put it another way, you simply never change an interface; if you need to, you create an entirely new interface. &lt;/P&gt;
&lt;P&gt;You may have wondered why is COM so strict about this rule. It’s because when you write a C++ program that uses an interface, the compiler will generate code that depends upon the particular pattern of stack frame layouts for passing arguments remaining exactly the same even when the user installs a new version of the COM object on their machine. Because COM objects and their “clients” can be versioned independently, the &lt;SPAN class=code&gt;GUID&lt;/SPAN&gt; has to be associated with a particular “binary contract” describing how the two pieces of code communicate. &lt;/P&gt;
&lt;P&gt;Now, the script engines always talk to scriptable objects via &lt;SPAN class=code&gt;IDispatch&lt;/SPAN&gt; or &lt;SPAN class=code&gt;IDispatchEx&lt;/SPAN&gt;, so if a scriptable object accidentally breaks its contract, the script engines don’t notice a bit. They let the dispatch layer take care of all those irksome details about stack frame layout, and the dispatch layer figures all this stuff out from the type library data in the object itself. &lt;/P&gt;
&lt;P&gt;Perhaps you see where this is going. &lt;/P&gt;
&lt;P&gt;The &lt;SPAN class=code&gt;Replace&lt;/SPAN&gt; method of the VBScript regular expression object originally took two “in” arguments, both strings, and returned a string. This was the &lt;SPAN class=code&gt;IRegExp&lt;/SPAN&gt; interface. Later we realized that we wanted to be able to pass things other than strings for the second argument, so we created a new &lt;SPAN class=code&gt;IRegExp2&lt;/SPAN&gt; interface where the &lt;SPAN class=code&gt;Replace&lt;/SPAN&gt; method took a string and a variant, and returned a string. So far, so good. &lt;/P&gt;
&lt;P&gt;Then we ported the script engines to the IA64 processor. During the port for some unknown reason one of the developers temporarily changed the second argument from a &lt;SPAN class=code&gt;VARIANT&lt;/SPAN&gt; to a &lt;SPAN class=code&gt;VARIANT*&lt;/SPAN&gt;, put a comment in the code saying that this needed to be changed back before it was checked in, checked it in, and, uh, we kinda shipped it like that. &lt;/P&gt;
&lt;P&gt;We thoroughly violated the rules of COM, but none of our automated tests showed this, because of course, all of the scripting automated tests were written – you guessed it – in &lt;I&gt;script&lt;/I&gt;. &lt;B&gt;We had no tests which used the scriptable objects from early-bound code.&lt;/B&gt; (We do now!) &lt;/P&gt;
&lt;P&gt;Unfortunately, some of our developer customers were using the VBScript regular expression object from C++ and other early bound languages, so as soon as &lt;EM&gt;their&lt;/EM&gt; customers upgraded to the latest version of scripting, all hell broke loose. The caller was fulfilling their end of the contract by putting a sixteen byte variant on the stack, and the callee was suddenly expecting a four byte pointer to a variant, so it was both crashing and misaligning the stack. &lt;/P&gt;
&lt;P&gt;We &lt;I&gt;immediately&lt;/I&gt; started getting bug reports, of course. About half the bug reports said “please change this back ASAP, our customers are broken”, and the other half said “we have already shipped a patch of our code to our customers using the new stack layout, please do not change it back, ever, we do not want to ship another patch”. &lt;/P&gt;
&lt;P&gt;Obviously we realized that we had badly screwed up and were now in a hideous bind. We came up with three options: &lt;/P&gt;
&lt;P&gt;First, we could revert to the previous layout, and inconvenience the small number of customers who had already shipped patches to &lt;I&gt;their&lt;/I&gt; customers. (And of course, inconvenience all of those people as well, who would have to apply a second patch in as many days.) &lt;/P&gt;
&lt;P&gt;Second, we could keep the current layout and tell the rest of our affected customers that they needed to patch our mistake. &lt;/P&gt;
&lt;P&gt;Third, we could revert to the previous layout and yet NOT inconvenience anyone. &lt;/P&gt;
&lt;P&gt;Obviously the third option is best, but how to do it? &lt;/P&gt;
&lt;P&gt;I ended up writing heuristics into the &lt;SPAN class=code&gt;Replace&lt;/SPAN&gt; method that examined the stack frame, and then rerouted the call to a special helper method if we detected a &lt;SPAN class=code&gt;VARIANT*&lt;/SPAN&gt; on the stack when we were expecting a &lt;SPAN class=code&gt;VARIANT&lt;/SPAN&gt;. The helper method did all the necessary magic to adjust the stack pointer, and so on, so that from the caller’s perspective, everything looked perfectly normal. &lt;/P&gt;
&lt;P&gt;Now, remember, we expected that in the vast majority of cases, a &lt;SPAN class=code&gt;VARIANT&lt;/SPAN&gt; would be passed, not a &lt;SPAN class=code&gt;VARIANT*&lt;/SPAN&gt;. My heuristic detected which case we were in by extracting four bytes from the middle of the stack frame and calling &lt;SPAN class=code&gt;IsBadReadPtr&lt;/SPAN&gt; on it. If that was a valid pointer then I’d cast it to a &lt;SPAN class=code&gt;VARIANT*&lt;/SPAN&gt;, check to see whether the variant type field was a string (by far the most likely argument to &lt;SPAN class=code&gt;Replace&lt;/SPAN&gt;), and then call &lt;SPAN class=code&gt;IsBadWritePtr&lt;/SPAN&gt; on the &lt;SPAN class=code&gt;bstrVal&lt;/SPAN&gt; (because &lt;SPAN class=code&gt;BSTR&lt;/SPAN&gt; pointers are &lt;A href="http://blogs.msdn.com/ericlippert/archive/2003/09/12/52976.aspx"&gt;almost always writeable&lt;/A&gt;). There were a few other details to the heuristic, but the point is that in the vast majority of cases, &lt;SPAN class=code&gt;IsBadReadPtr&lt;/SPAN&gt; was expected to fail. Only in the rare cases where we were in an early-bound and third-party patched program should it succeed. &lt;/P&gt;
&lt;P&gt;We shipped the fixed version with the heuristics out immediately. &lt;/P&gt;
&lt;P&gt;At the time I did not realize how &lt;SPAN class=code&gt;IsBadReadPtr&lt;/SPAN&gt; was implemented. It actually puts a &lt;SPAN class=code&gt;try-except&lt;/SPAN&gt; around an attempt to read the pointer! If it gets an exception then it&amp;nbsp;eats the exception and says yeah, it's bad. Essentially what I had done was inserted an almost-always-thrown exception into every call to &lt;SPAN class=code&gt;Replace&lt;/SPAN&gt;. &lt;/P&gt;
&lt;P&gt;My goal of not inconveniencing anyone turned out to not quite work out as planned. The Active Server Pages team went nuts that afternoon. Their tests assume that all exceptions, whether handled or not, are flaws somewhere in ASP or scripting. Their test machines are all configured to track and report &lt;I&gt;all&lt;/I&gt; first-chance exceptions, and suddenly every compatibility and stress test machine they had that happened to do a regular expression replace – that is, approximately all of them – suddenly started reporting hundreds of first-chance exceptions per minute when they upgraded to the latest released version. &lt;/P&gt;
&lt;P&gt;So just when I thought that I could breathe easy again for a few minutes I started getting calls from the now highly vexed ASP team. I ended up writing my own versions of &lt;SPAN class=code&gt;IsBadFooPtr&lt;/SPAN&gt; which do the right thing – they call &lt;SPAN class=code&gt;VirtualQuery&lt;/SPAN&gt; to ask the operating system what the protection state of a given address is, rather than simply trying it out and throwing a first-chance exception on failure. &lt;/P&gt;
&lt;P&gt;Long story short: don’t change an interface, don’t call &lt;SPAN class=code&gt;IsBadFooPtr&lt;/SPAN&gt;, and run your changes by &lt;I&gt;all&lt;/I&gt; your important consumers &lt;I&gt;before&lt;/I&gt; you ship a tricky fix! &lt;/P&gt;&lt;/DIV&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=774117" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/ericlippert/archive/tags/VBScript/default.aspx">VBScript</category><category domain="http://blogs.msdn.com/ericlippert/archive/tags/COM+Programming/default.aspx">COM Programming</category></item><item><title>Checking For Script Syntax Errors, This Time With Code</title><link>http://blogs.msdn.com/ericlippert/archive/2005/10/12/480154.aspx</link><pubDate>Wed, 12 Oct 2005 19:37:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:480154</guid><dc:creator>Eric Lippert</dc:creator><slash:comments>9</slash:comments><comments>http://blogs.msdn.com/ericlippert/comments/480154.aspx</comments><wfw:commentRss>http://blogs.msdn.com/ericlippert/commentrss.aspx?PostID=480154</wfw:commentRss><description>&lt;FONT face="lucida sans unicode" color=purple size=2&gt;
&lt;P&gt;A number of people asked me to clarify yesterday's entry.&amp;nbsp;Rather than try to talk you through it, I think the code is straightforward enough to speak for itself.&amp;nbsp;Here's a little skeleton that I just whipped up.&lt;/P&gt;&lt;/FONT&gt;&lt;FONT face="lucida console" color=navy size=2&gt;
&lt;P&gt;#include &amp;lt;stdio.h&amp;gt;&lt;BR&gt;#include &amp;lt;activscp.h&amp;gt;&lt;BR&gt;#include &amp;lt;new&amp;gt;&lt;/P&gt;
&lt;P&gt;const GUID CLSID_VBScript = {0xb54f3741, 0x5b07, 0x11cf, {0xa4, 0xb0, 0x00, 0xaa, 0x00, 0x4a, 0x55, 0xe8}};&lt;BR&gt;const GUID CLSID_JScript&amp;nbsp; = {0xf414c260, 0x6ac0, 0x11cf, {0xb6, 0xd1, 0x00, 0xaa, 0x00, 0xbb, 0xbb, 0x58}};&lt;/P&gt;
&lt;P&gt;class MySite : public IActiveScriptSite {&lt;BR&gt;private:&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;ULONG m_cref;&lt;BR&gt;&amp;nbsp; virtual ~MySite() {}&lt;/P&gt;
&lt;P&gt;public:&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;MySite() {&lt;BR&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;this-&amp;gt;m_cref = 1;&lt;BR&gt;&amp;nbsp;&amp;nbsp;}&lt;/P&gt;
&lt;P&gt;&amp;nbsp; STDMETHOD_(ULONG, AddRef)() {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return ++this-&amp;gt;m_cref;&lt;BR&gt;&amp;nbsp;&amp;nbsp;}&lt;/P&gt;
&lt;P&gt;&amp;nbsp; STDMETHOD_(ULONG,Release)() {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; --this-&amp;gt;m_cref;&lt;BR&gt;&amp;nbsp; &amp;nbsp;&amp;nbsp;if (this-&amp;gt;m_cref == 0) {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;delete this;&lt;BR&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;return 0;&lt;BR&gt;&amp;nbsp; &amp;nbsp;&amp;nbsp;}&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return this-&amp;gt;m_cref;&lt;BR&gt;&amp;nbsp;&amp;nbsp;}&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;STDMETHOD(QueryInterface)(REFIID iid, void ** ppv) {&lt;BR&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;if (ppv == NULL)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;return E_POINTER;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (IsEqualIID(iid, IID_IUnknown))&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;*ppv = (IUnknown*)this;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; else if (IsEqualIID(iid, IID_IActiveScriptSite))&lt;BR&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;*ppv = (IActiveScriptSite*)this;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; else {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;*ppv = NULL;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;return E_NOINTERFACE;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; this-&amp;gt;AddRef();&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return S_OK;&lt;BR&gt;&amp;nbsp; }&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;STDMETHOD(GetLCID)(LCID * plcid) {&lt;BR&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;return E_NOTIMPL;&lt;BR&gt;&amp;nbsp; }&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;STDMETHOD(GetItemInfo)(&lt;BR&gt;&amp;nbsp; &amp;nbsp;&amp;nbsp;LPCOLESTR pstrName,&lt;BR&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;DWORD dwReturnMask,&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; IUnknown ** ppunkItem,&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; ITypeInfo ** ppti) {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return E_NOTIMPL;&lt;BR&gt;&amp;nbsp;&amp;nbsp;}&lt;/P&gt;
&lt;P&gt;&amp;nbsp; STDMETHOD(GetDocVersionString)(BSTR * pbstrVersion) {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return E_NOTIMPL;&lt;BR&gt;&amp;nbsp; }&lt;/P&gt;
&lt;P&gt;&amp;nbsp; STDMETHOD(OnScriptTerminate)(&lt;BR&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;const VARIANT * pvarResult,&lt;BR&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;const EXCEPINFO * pexcepinfo) {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return S_OK;&lt;BR&gt;&amp;nbsp;&amp;nbsp;}&lt;/P&gt;
&lt;P&gt;&amp;nbsp; STDMETHOD(OnStateChange)(SCRIPTSTATE state) {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return S_OK;&lt;BR&gt;&amp;nbsp;&amp;nbsp;}&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;STDMETHOD(OnEnterScript)() {&lt;BR&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;return S_OK;&lt;BR&gt;&amp;nbsp; }&lt;BR&gt;&amp;nbsp;&lt;BR&gt;&amp;nbsp; STDMETHOD(OnLeaveScript)() {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return S_OK;&lt;BR&gt;&amp;nbsp;&amp;nbsp;}&lt;/P&gt;
&lt;P&gt;&amp;nbsp; STDMETHOD(OnScriptError)(IActiveScriptError * perror) {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; EXCEPINFO excepinfo;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; LONG column = 0;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; ULONG line = 0;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; DWORD context = 0;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; BSTR bstrLine = NULL;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; memset(&amp;amp;excepinfo, 0x00, sizeof excepinfo);&lt;BR&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;perror-&amp;gt;GetExceptionInfo(&amp;amp;excepinfo);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (excepinfo.pfnDeferredFillIn != NULL)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;excepinfo.pfnDeferredFillIn(&amp;amp;excepinfo);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; perror-&amp;gt;GetSourceLineText(&amp;amp;bstrLine);&lt;BR&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;perror-&amp;gt;GetSourcePosition(&amp;amp;context, &amp;amp;line, &amp;amp;column);&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;wprintf(L"Error on line %ld column %ld\n", line, column);&lt;BR&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;if (bstrLine != NULL)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; wprintf(L"Line: %s\n", bstrLine);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (excepinfo.bstrDescription != NULL)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;wprintf(L"Description: %s\n", excepinfo.bstrDescription);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (excepinfo.bstrSource != NULL)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;wprintf(L"Source: %s\n", excepinfo.bstrSource);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (excepinfo.bstrHelpFile != NULL)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;wprintf(L"Help: %s\n", excepinfo.bstrHelpFile);&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; SysFreeString(bstrLine);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; SysFreeString(excepinfo.bstrDescription);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; SysFreeString(excepinfo.bstrSource);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; SysFreeString(excepinfo.bstrHelpFile);&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return S_OK;&lt;BR&gt;&amp;nbsp; }&lt;BR&gt;};&lt;/P&gt;
&lt;P&gt;void main() {&lt;BR&gt;&amp;nbsp; HRESULT hr = S_OK;&lt;BR&gt;&amp;nbsp; HRESULT hrInit;&lt;BR&gt;&amp;nbsp; IClassFactory * pfactory = NULL;&lt;BR&gt;&amp;nbsp; IActiveScript * pscript = NULL;&lt;BR&gt;&amp;nbsp; IActiveScriptParse * pparse = NULL;&lt;BR&gt;&amp;nbsp; IActiveScriptSite * psite = NULL;&lt;/P&gt;
&lt;P&gt;&amp;nbsp; hr = hrInit = OleInitialize(NULL);&lt;BR&gt;&amp;nbsp; if (FAILED(hr))&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; goto LError;&lt;/P&gt;
&lt;P&gt;&amp;nbsp; hr = CoGetClassObject(CLSID_VBScript, CLSCTX_SERVER, NULL, &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; IID_IClassFactory, (void**)&amp;amp;pfactory);&lt;BR&gt;&amp;nbsp; if (FAILED(hr))&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; goto LError;&lt;/P&gt;
&lt;P&gt;&amp;nbsp; hr = pfactory-&amp;gt;CreateInstance(NULL, IID_IActiveScript, (void**)&amp;amp;pscript);&lt;BR&gt;&amp;nbsp; if (FAILED(hr))&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; goto LError;&lt;/P&gt;
&lt;P&gt;&amp;nbsp; psite = new(std::nothrow) MySite();&lt;BR&gt;&amp;nbsp; if (psite == NULL) {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; hr = E_OUTOFMEMORY;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; goto LError;&lt;BR&gt;&amp;nbsp; }&lt;/P&gt;
&lt;P&gt;&amp;nbsp; hr = pscript-&amp;gt;SetScriptSite(psite);&lt;BR&gt;&amp;nbsp; if (FAILED(hr))&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; goto LError;&lt;/P&gt;
&lt;P&gt;&amp;nbsp; hr = pscript-&amp;gt;QueryInterface(IID_IActiveScriptParse, (void**)&amp;amp;pparse);&lt;BR&gt;&amp;nbsp; if (FAILED(hr))&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; goto LError;&lt;/P&gt;
&lt;P&gt;&amp;nbsp; hr = pparse-&amp;gt;ParseScriptText(L"Function Foo \n Foo = 123 \n End Funtcion \n",&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; NULL, NULL, NULL, 0, 1, 0, NULL, NULL);&lt;/P&gt;
&lt;P&gt;&amp;nbsp; if (FAILED(hr))&lt;BR&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;goto LError;&lt;BR&gt;&amp;nbsp;&lt;BR&gt;LError:&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;if (FAILED(hr))&lt;BR&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;printf("%0x\n", hr);&lt;/P&gt;
&lt;P&gt;&amp;nbsp; if (pparse != NULL)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; pparse-&amp;gt;Release();&lt;/P&gt;
&lt;P&gt;&amp;nbsp; if (psite != NULL)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; psite-&amp;gt;Release();&lt;/P&gt;
&lt;P&gt;&amp;nbsp; if (pscript != NULL) {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; pscript-&amp;gt;Close();&lt;BR&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;pscript-&amp;gt;Release();&lt;BR&gt;&amp;nbsp;&amp;nbsp;}&lt;/P&gt;
&lt;P&gt;&amp;nbsp; if (pfactory != NULL)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; pfactory-&amp;gt;Release();&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;if (SUCCEEDED(hrInit))&lt;BR&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;OleUninitialize();&lt;BR&gt;}&lt;/P&gt;&lt;FONT face="lucida sans unicode" color=purple size=2&gt;
&lt;P&gt;As you would expect, this program prints out the information about the error, and ParseScriptText returns SCRIPT_E_REPORTED to indicate that there was an error but it has already been reported. Had there been no error, the script would not have actually&amp;nbsp;run; the engine is not &lt;STRONG&gt;started&lt;/STRONG&gt;, just &lt;STRONG&gt;initialized&lt;/STRONG&gt;.&lt;/P&gt;&lt;/FONT&gt;
&lt;P&gt;Error on line 3 column 5&lt;BR&gt;Line:&amp;nbsp; End Funtcion&lt;BR&gt;Description: Expected 'Function'&lt;BR&gt;Source: Microsoft VBScript compilation error&lt;BR&gt;80020101&lt;/P&gt;&lt;/FONT&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=480154" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/ericlippert/archive/tags/JScript/default.aspx">JScript</category><category domain="http://blogs.msdn.com/ericlippert/archive/tags/VBScript/default.aspx">VBScript</category><category domain="http://blogs.msdn.com/ericlippert/archive/tags/Scripting/default.aspx">Scripting</category><category domain="http://blogs.msdn.com/ericlippert/archive/tags/COM+Programming/default.aspx">COM Programming</category></item><item><title>Checking For Script Syntax Errors</title><link>http://blogs.msdn.com/ericlippert/archive/2005/10/11/479696.aspx</link><pubDate>Tue, 11 Oct 2005 20:35:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:479696</guid><dc:creator>Eric Lippert</dc:creator><slash:comments>8</slash:comments><comments>http://blogs.msdn.com/ericlippert/comments/479696.aspx</comments><wfw:commentRss>http://blogs.msdn.com/ericlippert/commentrss.aspx?PostID=479696</wfw:commentRss><description>&lt;FONT face="lucida sans unicode" color=purple size=2&gt;
&lt;P&gt;A reader asked me recently whether there was a way to check a chunk of JScript or VBScript for syntax errors without actually running the code. I'm sure that there are many third-party tools which you could find that do this. If you have your own script host, you can do it yourself quite easily.&lt;/P&gt;
&lt;P&gt;The trick is to initialize the engine by setting the script site, but do not do anything that would move the engine from initialized into started state. (Note that attempting to evaluate an expression moves the engine to started state.) &lt;/P&gt;
&lt;P&gt;If the engine is initialzed but not started then calling &lt;FONT color=#000080&gt;ParseScriptText&lt;/FONT&gt; will check the text passed in for syntax errors but will not run the script.&amp;nbsp;Rather, if the script compiles successfully, it is simply marked as "needs to run when the engine is started".&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Unfortunately the script engines do not have an error-recovering parser, so they will detect only the first syntax error and then bail out. Still, better than nothing.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;/FONT&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=479696" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/ericlippert/archive/tags/JScript/default.aspx">JScript</category><category domain="http://blogs.msdn.com/ericlippert/archive/tags/VBScript/default.aspx">VBScript</category><category domain="http://blogs.msdn.com/ericlippert/archive/tags/Scripting/default.aspx">Scripting</category></item><item><title>Implementing Event Handling, Part Two</title><link>http://blogs.msdn.com/ericlippert/archive/2005/09/21/472465.aspx</link><pubDate>Wed, 21 Sep 2005 21:51:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:472465</guid><dc:creator>Eric Lippert</dc:creator><slash:comments>3</slash:comments><comments>http://blogs.msdn.com/ericlippert/comments/472465.aspx</comments><wfw:commentRss>http://blogs.msdn.com/ericlippert/commentrss.aspx?PostID=472465</wfw:commentRss><description>&lt;FONT face="lucida sans unicode" color=purple size=2&gt;
&lt;P&gt;It's been an insanely busy month for me, between having multiple out-of-town guests, throwing a party for the people who couldn't make it to the wedding, and oh yeah, getting up to speed on the C# compiler and trying to understand the implications that LINQ features are going to have on the current implementation.&amp;nbsp; Not much time for blogging.&amp;nbsp;Hopefully October will be a little bit more under control.&lt;/P&gt;
&lt;P&gt;Anyway, &lt;a href="http://blogs.msdn.com/ericlippert/archive/2005/09/09/463215.aspx"&gt;I was talking about early-bound event binding&lt;/A&gt;. Basically the idea is that the source and the sink agree upon an interface that the source can call on the sink whenever the source wishes to fire an event. Before we get into that more, I want to talk briefly about early- and late-bound code.&lt;/P&gt;
&lt;P&gt;At an implementation level, what is the difference between early- and late- bound code? In the early-bound world, a particular function on an interface&amp;nbsp;gets called&amp;nbsp;when the caller&amp;nbsp;dereferences the callee's virtual function table and transfers control directly to the function by changing the instruction pointer on the chip.&amp;nbsp;In the late-bound world, the caller calls &lt;FONT color=#000080&gt;IDispatch::Invoke&lt;/FONT&gt; and passes in a magic number that tells the callee what function it should be calling, and the callee is then responsible for dispatching the function appropriately. (Hence the name "&lt;FONT color=#000080&gt;IDispatch&lt;/FONT&gt;".)&lt;/P&gt;
&lt;P&gt;The script engines use &lt;FONT color=#000080&gt;IDispatch&lt;/FONT&gt; all the time to call out to functions on objects. When calling an object late-bound, you don't know until you actually try the call whether or not it is going to succeed, because you do not know the interface the object implements.&amp;nbsp; So you call &lt;FONT color=#000080&gt;GetIdsOfNames&lt;/FONT&gt; to get the magic number associated with a particular function, Invoke on that magic number,&amp;nbsp;and let the callee sort it out. In this situation, the caller (the script engine)&amp;nbsp;knows the name of the function it wants to call, and the callee (the object)&amp;nbsp;can map the name to the appropriate identifier.&lt;/P&gt;
&lt;P&gt;Now consider how this works if &lt;FONT color=#000080&gt;IDispatch&lt;/FONT&gt; is the interface over which the source (the object) is calling back the sink (the script host). This &lt;EM&gt;appears&lt;/EM&gt; to be the same situation, but in fact it is completely different.&amp;nbsp; It appears the same because from the perspective of how COM actually manages all the calls, its exactly the same.&amp;nbsp; &lt;FONT color=#000080&gt;IDispatch&lt;/FONT&gt; is an interface like any other, and the source can call the sink's &lt;FONT color=#000080&gt;IDispatch&lt;/FONT&gt; to its heart's content if that's the interface that they agree to talk over.&lt;/P&gt;
&lt;P&gt;But look at it from the point of view of the sink: the &lt;EM&gt;caller&lt;/EM&gt; knows what the magic number means and the callee does not, but it's the callee who is being asked to do the dispatching!&amp;nbsp;You're sitting there sinking events of who knows what object, and every now and then you get a call on &lt;FONT color=#000080&gt;IDispatch::Invoke&lt;/FONT&gt; with some unknown dispid.&amp;nbsp; What the heck are you supposed to do with that?&amp;nbsp; In the late-bound world, instead of getting a nice direct call on "&lt;FONT color=#000080&gt;Tick()... Tick()...&amp;nbsp; Tick()...&lt;/FONT&gt;"&amp;nbsp; you're getting "12...&amp;nbsp; 12...&amp;nbsp; 12..." and &lt;EM&gt;you have no idea what "12" means.&lt;BR&gt;&lt;/EM&gt;&amp;nbsp;&lt;BR&gt;Let's tie this in to scripting.&amp;nbsp; Suppose you're in Windows Script Host and you do something like:&lt;BR&gt;&amp;nbsp;&lt;BR&gt;&lt;FONT color=#000080&gt;Sub Timer_Tick()&lt;BR&gt;&amp;nbsp; 'whatever&lt;BR&gt;End Sub&lt;BR&gt;Set Timer = CreateObject("mytimer")&lt;BR&gt;WScript.ConnectObject Timer, "Timer_"&lt;BR&gt;Timer.Start 10&lt;BR&gt;WScript.Sleep 1000&lt;/FONT&gt;&lt;BR&gt;&amp;nbsp;&lt;BR&gt;&lt;FONT color=#000080&gt;&lt;FONT color=#800080&gt;There are many&amp;nbsp;&lt;FONT color=#000080&gt;IDispatch&lt;/FONT&gt; objects here and we'll look at three of them.&amp;nbsp;First, there's the source, that is, the timer object.&amp;nbsp;Then there's the sink, owned by the host and created when the source is connected to it.&amp;nbsp;Finally there is the script engine itself, upon which the host can dispatch calls to global functions such as the event handler.&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#000080&gt;ConnectObject&lt;/FONT&gt;&amp;nbsp;is given a source&amp;nbsp;object.&amp;nbsp; It has no idea what early-bound &lt;EM&gt;outgoing&lt;/EM&gt; interface is on that object, and it certainly doesn't have an implementation of such an interface even if there is one, so it is going to have to do a late bound sink.&amp;nbsp; It creates an object to act as the sink, gets an &lt;FONT color=#000080&gt;IDispatch&lt;/FONT&gt;-enabled connection point from the source, and advises it.&lt;BR&gt;&amp;nbsp;&lt;BR&gt;Now the script engine calls &lt;FONT color=#000080&gt;Start&lt;/FONT&gt; (via &lt;FONT color=#000080&gt;IDispatch &lt;/FONT&gt;on the source)&amp;nbsp;and goes to sleep.&amp;nbsp; &lt;/P&gt;
&lt;P&gt;Pretty soon the timer invokes the sink, passing in the dispatch identifier for &lt;FONT color=#000080&gt;Tick&lt;/FONT&gt;.&amp;nbsp;&amp;nbsp;&lt;BR&gt;&lt;BR&gt;The sink&amp;nbsp;needs to know which sub to call in the script engine.&amp;nbsp; &lt;/P&gt;
&lt;P&gt;Fortunately, it has an &lt;FONT color=#000080&gt;IDispatch&lt;/FONT&gt; pointer to the source, and a dispatch identifier.&amp;nbsp; &lt;/P&gt;
&lt;P&gt;Unfortunately, though &lt;FONT color=#000080&gt;IDispatch&lt;/FONT&gt; provides a function which maps from name to id, it provides no function&amp;nbsp;that&amp;nbsp;maps the other way. &lt;/P&gt;
&lt;P&gt;Fortunately, &lt;FONT color=#000080&gt;IDispatch&lt;/FONT&gt; &lt;EM&gt;does&lt;/EM&gt; provide a function that enables the host to obtain a type information structure which contains a list of all the methods and what their dispatch identifiers are. Therefore&amp;nbsp;we can search all the methods in the type info and check to see which has the desired dispatch identifier.&amp;nbsp; That then gives us the method name, so we know which event handler function to dispatch on the script engine. &lt;/P&gt;
&lt;P&gt;Unfortunately there is a major design flaw in &lt;FONT color=#000080&gt;IDispatch&lt;/FONT&gt; -- it gives you the&amp;nbsp;type info for the incoming interface -- the &lt;FONT color=#000080&gt;ITimer&lt;/FONT&gt;.&amp;nbsp; But there is no way to take the &lt;FONT color=#000080&gt;ITypeInfo&lt;/FONT&gt; for &lt;FONT color=#000080&gt;ITimer&lt;/FONT&gt; and say "give me the type info &lt;EM&gt;for the class as a whole&lt;/EM&gt; so that I can obtain the type info for the &lt;EM&gt;outgoing&lt;/EM&gt; interface".&lt;BR&gt;&amp;nbsp;&lt;BR&gt;Fortunately,&amp;nbsp;&lt;FONT color=#000080&gt;IProvideClassInfo&lt;/FONT&gt; was invented.&amp;nbsp; IPCI gives you back the "root" type info for an object, from which you can obtain a type info for the default outgoing interface, from which you can map the dispatch identifier to the name.&lt;/P&gt;
&lt;P&gt;Unfortunately, many objects do not implement &lt;FONT color=#000080&gt;IProvideClassInfo&lt;/FONT&gt;, and therefore cannot&amp;nbsp;have their events hooked up by&amp;nbsp;&lt;FONT color=#000080&gt;ConnectObject&lt;/FONT&gt;.&lt;/P&gt;
&lt;P&gt;(I feel a little bit like the ending of Dr. Strangelove here.&amp;nbsp; Fortunately, they stop General Ripper in time.&amp;nbsp; Unfortunately, the secret code died with him. Fortunately they figure out the code. Unfortunately, the radio is broken.&amp;nbsp; Fortunately, the bomb bay doors are stuck. Unfortunately, they fix them, and the Doomsday Device destroys the world. Bummer.)&lt;/P&gt;
&lt;P&gt;The moral of this story is simple: &lt;STRONG&gt;for late bound events to work, at some point the class of the source must be known&lt;/STRONG&gt;. And therefore:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;"automagic event binding" in IE only works on "named items" present in the script engine.&amp;nbsp; (The script engines require that the host provide a coclass type info for named items, and build the sinks very early on, before other code runs.) 
&lt;LI&gt;&lt;FONT color=#000080&gt;WScript.CreateObject&lt;/FONT&gt; can &lt;EM&gt;always&lt;/EM&gt; hook up events. The class type info is known because &lt;FONT color=#000080&gt;CreateObject&lt;/FONT&gt; had to create an instance of the class. 
&lt;LI&gt;&lt;FONT color=#000080&gt;WScript.ConnectObject&lt;/FONT&gt; can hook up events&amp;nbsp;only if&amp;nbsp;the object implements &lt;FONT color=#000080&gt;IProvideClassInfo&lt;/FONT&gt;&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;I hope that clears up any confusion about what &lt;FONT color=#000080&gt;IProvideClassInfo&lt;/FONT&gt; is for!&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;/FONT&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=472465" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/ericlippert/archive/tags/JScript/default.aspx">JScript</category><category domain="http://blogs.msdn.com/ericlippert/archive/tags/VBScript/default.aspx">VBScript</category><category domain="http://blogs.msdn.com/ericlippert/archive/tags/Scripting/default.aspx">Scripting</category><category domain="http://blogs.msdn.com/ericlippert/archive/tags/COM+Programming/default.aspx">COM Programming</category></item><item><title>250% of what, exactly?</title><link>http://blogs.msdn.com/ericlippert/archive/2005/09/01/459166.aspx</link><pubDate>Thu, 01 Sep 2005 20:13:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:459166</guid><dc:creator>Eric Lippert</dc:creator><slash:comments>27</slash:comments><comments>http://blogs.msdn.com/ericlippert/comments/459166.aspx</comments><wfw:commentRss>http://blogs.msdn.com/ericlippert/commentrss.aspx?PostID=459166</wfw:commentRss><description>&lt;FONT face="Lucida sans unicode"&gt;&lt;FONT color=#800080 size=2&gt;
&lt;P&gt;I&amp;nbsp;just got a question this morning about how to take two collections of items and determine how many of those items had the same name. The user had written this straightforward but extremely slow VBScript algorithm:&lt;/P&gt;&lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;
&lt;P&gt;For Each Frog In Frogs&lt;BR&gt;&amp;nbsp; For Each Toad In Toads&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; If Frog.Name = Toad.Name Then&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; SameName = SameName + 1&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Exit For&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; End If&lt;BR&gt;&amp;nbsp; Next&lt;BR&gt;Next&lt;/P&gt;&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt;
&lt;P&gt;There were about 5000 frogs, 3000 toads and 1500 of them had the same name. Every one of the 3500 unsuccessful searches checked all 3000 toads, and the 1500 successful searches on average checked 1500 toads each. Each time through the inner loop does one loop iteration, two calls to the Name property, one string comparison. Add all those up and you get roughly 50 million function calls to determine this count. &lt;/P&gt;
&lt;P&gt;This code has been somewhat simplified – the actual user code was doing more work inside the loop, including calls to WMI objects. The whole thing was taking 10+ minutes, which is actually pretty fast considering how much work was being done. Each individual function call was only taking a few microseconds, but fifty million calls adds up!&lt;/P&gt;
&lt;P&gt;Now, we've been down this road before in this blog (&lt;/FONT&gt;&lt;a href="http://blogs.msdn.com/ericlippert/archive/2004/05/12/130840.aspx"&gt;&lt;U&gt;&lt;FONT color=#0000ff size=2&gt;here&lt;/U&gt;&lt;/FONT&gt;&lt;/A&gt;&lt;FONT color=#800080 size=2&gt;, &lt;/FONT&gt;&lt;a href="http://blogs.msdn.com/ericlippert/archive/2004/05/13/131533.aspx"&gt;&lt;U&gt;&lt;FONT color=#0000ff size=2&gt;here&lt;/U&gt;&lt;/FONT&gt;&lt;/A&gt;&lt;FONT color=#800080 size=2&gt; and &lt;/FONT&gt;&lt;a href="http://blogs.msdn.com/ericlippert/archive/2004/05/14/132160.aspx"&gt;&lt;U&gt;&lt;FONT color=#0000ff size=2&gt;here&lt;/U&gt;&lt;/FONT&gt;&lt;/A&gt;&lt;FONT color=#800080 size=2&gt;) and so of course I recommended building a faster lookup table rather than doing a full search through the collection every time.&lt;/P&gt;&lt;/FONT&gt;&lt;FONT face=Arial size=2&gt;&lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;
&lt;P&gt;Set FrogLookup = CreateObject("Scripting.Dictionary")&lt;BR&gt;For Each Frog In Frogs&lt;BR&gt;&amp;nbsp; FrogLookup(Frog.Name) = Frog&lt;BR&gt;Next&lt;BR&gt;For Each Toad In Toads&lt;BR&gt;&amp;nbsp; If FrogLookup.Exists(Toad.Name) Then SameName = SameName + 1&lt;BR&gt;Next&lt;/P&gt;&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt;
&lt;P&gt;Which is much, much faster. That's only about 16 thousand function calls. Now, this is maybe not an apples-to-apples comparison of function calls, but we at least have good reason to believe that this is going to be several times faster.&amp;nbsp;&lt;/P&gt;
&lt;P&gt;And indeed it was. But I'm still not sure how much, which brings me to the &lt;I&gt;actual subject&lt;/I&gt; of today's blog. The user reported that the new algorithm was "250% better". I hear results like this all the time, and I always have to ask to clarify what it means. You can't just say "n% better" without somehow also communicating what you're measuring. &lt;/P&gt;
&lt;P&gt;(UPDATE: This reported result understandably confused some readers.&amp;nbsp; Clearly the new loop here is &lt;EM&gt;thousands&lt;/EM&gt; of times faster, not a mere 250% faster. As I said before, the&amp;nbsp;sketch above is highly simplified code. The real-world code included many thousands of additional calls to WMI objects which were not eliminated by this optimization. Eliminating these 50 million function calls helped -- you should always eliminate the slowest thing first!&amp;nbsp; But doing so also exposed a new "hot spot" that needed further optimization.&amp;nbsp; However, the point of this article is not the benefits of using lookup tables, but rather that using unexplained percentages to report performance results is potentially misleading.&amp;nbsp; The result above is merely illustrative.&amp;nbsp; See the comments for more details.)&lt;/P&gt;
&lt;P&gt;Allow me to illustrate. Suppose I have a web server that is serving up ten thousand pages every ten seconds. I make a performance improvement to the page generator so that it is now serving up fifteen thousand pages every ten seconds. I can sensibly say:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;performance has improved by 50%, because we are now serving up 5000 more pages every ten seconds, and 5000 is 50% of the original 10000.&amp;nbsp; In this world, any positive percentage is good. 
&lt;LI&gt;performance is now 150% of original performance because 15000 is 150% of 10000.&amp;nbsp; In this world, 0%-100% worse or the same, 100%+ is good. 
&lt;LI&gt;We've gone from 1000 microseconds per page to 667 microseconds per page, saving 333 microseconds per page. 333 is 33% of 1000, so we've got a 33% performance improvement.&amp;nbsp; In this world, 0% is bad, 100% is perfect,&amp;nbsp; more than 100% is nonsensical.&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;If I can sensibly say that performance is better by 50%, 150% and 33%, all referring to exactly the same improvement, then I cannot actually be communicating any fact to my listeners! They need to know &lt;STRONG&gt;whether I'm measuring speed or time&lt;/STRONG&gt;, and if speed, whether I'm comparing &lt;STRONG&gt;original speed to new speed&lt;/STRONG&gt; or original &lt;STRONG&gt;speed to the difference.&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;So what is "250%" better? Clearly not raw timings. If this loop took 10 minutes to run before, 250% of 10 minutes is 25 minutes, but surely it is not running in -15 minutes now! I assume that the measurement is speed -- say, number of loops runnable per hour. If before it took ten minutes and therefore we could run this loop six times per hour, and now it is 250% better, 250% of 6 is 15, and this is "better", so we need to add. So that's 21 loops per hour, or about 3 minutes per loop.&amp;nbsp;Had the user accidentally said "250% faster" but meant to say&amp;nbsp;"250% of previous performance" then we'd conclude that 250% of 6 per hour&amp;nbsp;is 15 per hour, so now we've got 4 minutes per loop.&lt;/P&gt;
&lt;P&gt;And of course, this is assuming that the person reporting the improvement is actually trying to communicate facts to the audience. Be wary! Since 33%, 50% and 150% are all sensible ways to report this improvement, which do you think someone who wants to impress you is going to choose? There are opportunities here for what Kee Dewdney calls "percentage pumping" and other shyster tricks for making weak&amp;nbsp;numbers look more impressive. Professor Dewdney's book on the subject, "200% of Nothing", is quite entertaining.&lt;/P&gt;
&lt;P&gt;The moral of the story is: &lt;STRONG&gt;please do not report performance improvements in percentages&lt;/STRONG&gt;. Report performance improvements in terms of &lt;STRONG&gt;raw numbers with units attached&lt;/STRONG&gt;, such as "microseconds per call, before and after change", or "pages per second, before and after change". That gives the reader enough information to actually understand the result.&lt;/P&gt;
&lt;P&gt;(And the other moral is, of course, &lt;STRONG&gt;lookup tables are your friends&lt;/STRONG&gt;.)&lt;/P&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=459166" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/ericlippert/archive/tags/VBScript/default.aspx">VBScript</category><category domain="http://blogs.msdn.com/ericlippert/archive/tags/Scripting/default.aspx">Scripting</category><category domain="http://blogs.msdn.com/ericlippert/archive/tags/Performance/default.aspx">Performance</category></item><item><title>VBScript Default Property Semantics</title><link>http://blogs.msdn.com/ericlippert/archive/2005/08/30/458051.aspx</link><pubDate>Tue, 30 Aug 2005 20:15:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:458051</guid><dc:creator>Eric Lippert</dc:creator><slash:comments>10</slash:comments><comments>http://blogs.msdn.com/ericlippert/comments/458051.aspx</comments><wfw:commentRss>http://blogs.msdn.com/ericlippert/commentrss.aspx?PostID=458051</wfw:commentRss><description>&lt;FONT face="lucida sans unicode"&gt;&lt;FONT color=#800080 size=2&gt;
&lt;P&gt;Here’s a question I recently got about VBScript, where by "recently" I mean August 28th, 2003.&amp;nbsp;This code works just fine:&lt;/P&gt;&lt;/FONT&gt;&lt;FONT face=Arial size=2&gt;&lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;
&lt;P&gt;Set myObject = CreateObject("myObject")&lt;BR&gt;myObject.myName = "Eric" &lt;BR&gt;WScript.Echo myObject ' myName is the default property, so prints "Eric"&lt;/P&gt;&lt;/FONT&gt;&lt;FONT face=Arial size=2&gt;&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt;
&lt;P&gt;But &lt;FONT face="Lucida Console" color=#333399&gt;myObject = "Robert"&lt;/FONT&gt; doesn't set the default property, it sets the variable to the string. &lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt;Why does reading work but writing fail? This works in VB6, why not VBScript?&amp;nbsp;&lt;/P&gt;
&lt;P&gt;In a strongly typed language such as VB6 the compiler can look at the compile-time types of the left and right sides of an assignment and determine that the type of the left hand side is an object, the right hand side is a string, and the object has a default property which is a string.&amp;nbsp; The VB6 compiler can then generate the appropriate code to assign the string to the default property.&lt;/P&gt;
&lt;P&gt;But what if you wrote a VB6 program using only variants?&amp;nbsp; When the compiler sees &lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;foo = bar&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt; typed as variants it cannot tell whether this means "set the default property of &lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;foo&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt; to &lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;bar&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt;" or "set &lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;foo&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt; to &lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;bar&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt;".&amp;nbsp; The VB compiler chooses the latter every time. VBScript is a weakly typed subset of VB -- in VBScript, everything is a variant.&amp;nbsp; So in VBScript, all assignments are treated as though the value is actually being assigned to the variable, not the default property.&amp;nbsp;Therefore this is by design - this is for compatibility with VB6's behaviour.&amp;nbsp; Had&amp;nbsp;we written the same program in weakly-typed VB6, we'd get the same result.&amp;nbsp; &lt;/P&gt;
&lt;P&gt;I hear you exclaiming "The fact that a difference in available type information leads to a difference in run-time behaviour violates a basic principle of programming language design!&amp;nbsp; Namely, the principle that late-bound calls have exactly the same semantics as early-bound calls!"&amp;nbsp; &lt;/P&gt;
&lt;P&gt;Indeed, as I've mentioned before,&amp;nbsp;VB6 and VBScript violate this principle in several places.&amp;nbsp; Default properties were, in my opinion, a bad idea all around, for this and other reasons.&amp;nbsp; They make the language harder to parse and hence harder to understand.&amp;nbsp; In particular, &lt;EM&gt;parameterless&lt;/EM&gt; default properties make very little sense in VBScript.&amp;nbsp; However, we are stuck with them now.&lt;/P&gt;
&lt;P&gt;However, I should call out that there are some things we can do at runtime.&amp;nbsp;Suppose &lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;blah&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt; is an object with a property &lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;fred&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt; that is an object, and &lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;fred&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt; has a default property which is a string. If you say &lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;foo = blah.fred&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt; then &lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;foo&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt; &lt;I&gt;is&lt;/I&gt; assigned the default value of &lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;fred&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt; even though we lack the compile-time type information.&amp;nbsp; &lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;foo&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt; isn't set to the object &lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;fred. &lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt;Of course, in this case we know to fetch the default property at runtime &lt;I&gt;because we know the runtime type&lt;/I&gt; of &lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;fred&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt; and also know that there is no &lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;Set&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt; keyword.&amp;nbsp; These two facts are sufficient to cause the runtime engine to always fetch the default property.&lt;/P&gt;
&lt;P&gt;Or suppose you have an object &lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;Baz&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt; with a property &lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;Table&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt;, &lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;Table&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt; has a default &lt;I&gt;parameterized&lt;/I&gt; property &lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;Item&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt; which returns an object that has a string property &lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;Blah&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt;: Then this works just fine:&lt;/P&gt;&lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;
&lt;P&gt;x = Baz.Table(1).Blah&lt;/P&gt;&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt;
&lt;P&gt;But why? In this case we do &lt;I&gt;not&lt;/I&gt; have enough compile-time information to determine that we really should call &lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;Baz.Table.Item(1).Blah&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt;.&amp;nbsp; The script engine has every reason to believe that &lt;FONT color=#000080&gt;Table&lt;/FONT&gt; is a function or parameterized property of &lt;FONT color=#000080&gt;Baz&lt;/FONT&gt;.&amp;nbsp;This problem is solved by pushing it off to the implementation!&amp;nbsp;The rule for implementers of &lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;IDispatch::Invoke&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt; is if all of the following are true:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;the caller invokes a property 
&lt;LI&gt;the caller passes an argument list 
&lt;LI&gt;the property does not actually take an argument list 
&lt;LI&gt;that property returns an object 
&lt;LI&gt;that object has a default property 
&lt;LI&gt;that default property takes an argument list&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;then invoke the default property with the argument list.&amp;nbsp;Strange but true.&lt;/P&gt;
&lt;P&gt;Perhaps unsurprisingly, not very many people know about that rule!&amp;nbsp; This is yet another reason to never, ever write your own implementation of &lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;IDispatch::Invoke&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt;.&amp;nbsp; It also leads to some mind-numbingly complex code in the VBScript IntelliSense engine that Visual Studio uses.&amp;nbsp; Making default property IntelliSense work with such a dynamically typed language was a piece of work, lemme tell ya.&amp;nbsp;As I mentioned earlier, there are &lt;a href="http://blogs.msdn.com/ericlippert/archive/2004/05/04/125893.aspx"&gt;in fact some odd corner cases that are slightly different between VB6 and VBScript IntelliSense&lt;/A&gt;.&amp;nbsp; I also talked a bit about &lt;a href="http://blogs.msdn.com/ericlippert/archive/2004/05/04/125837.aspx"&gt;left-hand-side default property semantics &lt;/A&gt;earlier. &lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=458051" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/ericlippert/archive/tags/VBScript/default.aspx">VBScript</category><category domain="http://blogs.msdn.com/ericlippert/archive/tags/Scripting/default.aspx">Scripting</category><category domain="http://blogs.msdn.com/ericlippert/archive/tags/COM+Programming/default.aspx">COM Programming</category></item><item><title>Scripting Type Library Constant Injection Performance Characteristics, Part One</title><link>http://blogs.msdn.com/ericlippert/archive/2005/06/22/scripting-type-library-constant-injection-performance-characteristics-part-one.aspx</link><pubDate>Wed, 22 Jun 2005 17:00:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:430881</guid><dc:creator>Eric Lippert</dc:creator><slash:comments>1</slash:comments><comments>http://blogs.msdn.com/ericlippert/comments/430881.aspx</comments><wfw:commentRss>http://blogs.msdn.com/ericlippert/commentrss.aspx?PostID=430881</wfw:commentRss><description>&lt;FONT face="lucida sans unicode"&gt;&lt;FONT color=#800080 size=2&gt;
&lt;P&gt;(Sorry about the title. I work for Microsoft; &lt;a href="http://blogs.msdn.com/ericlippert/archive/2005/06/06/425847.aspx"&gt;we like nouns&lt;/A&gt;.)&lt;/P&gt;
&lt;P&gt;Over a year ago now a reader noted in a comment to &lt;/FONT&gt;&lt;a href="http://blogs.msdn.com/ericlippert/archive/2004/06/01/145686.aspx"&gt;&lt;U&gt;&lt;FONT color=#0000ff size=2&gt;this posting&lt;/U&gt;&lt;/FONT&gt;&lt;/A&gt;&lt;FONT color=#800080 size=2&gt; that defining named constants using &lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;Const&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt; in VBScript or &lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;var&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt; in JScript is way, way faster than importing a type library.&lt;/P&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;
&lt;P&gt;My empirical JScript testing showed that loading constants from a typelib is one or two orders of magnitude slower than preloading an engine with script which defines those same constants. &lt;/P&gt;&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt;
&lt;P&gt;I responded&lt;/P&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;
&lt;P&gt;I wrote all the type library importation code -- you are correct, it is NOT FAST compared to simply defining a bunch of consts/vars. There are good reasons why. I'll blog about them at some point. &lt;/P&gt;&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt;
&lt;P&gt;At long last I'll get around to explaining why. There are interesting design tradeoffs here, and as often happens in the scripting world, performance was traded off against ease-of-use. We're built for comfort, not speed. &lt;/FONT&gt;&lt;a href="http://blogs.msdn.com/ericlippert/archive/2003/10/17/53237.aspx"&gt;&lt;U&gt;&lt;FONT color=#0000ff size=2&gt;As I have said many times before, if you care about maximizing performance, using a late-bound unoptimized bytecode-interpreted dynamically-typed language is probably a bad choice.&lt;/U&gt;&lt;/FONT&gt;&lt;/A&gt;&lt;FONT color=#800080 size=2&gt; &lt;/P&gt;
&lt;P&gt;Let's go through the design process first, and then get into the implementation details and what the performance costs are.&lt;/P&gt;
&lt;P&gt;Let's make up a little syntax to describe the type libraries that I'm talking about. Note that this is &lt;B&gt;not VBScript&lt;/B&gt;, I just need a concise way to describe the enumerated type contents of a type library. (String constants in modules work the same way and nothing else in the library is relevant, so without loss of generality I'll be considering only enumerated types in this series.) I'll make it a bracy language to emphasize that this is not VBScript.&lt;/P&gt;&lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;
&lt;P&gt;typelib Video {&lt;BR&gt;&amp;nbsp; enum Color {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Red = 1&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Green = 2&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Blue = 3&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Black = 4&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; White = 5&lt;BR&gt;&amp;nbsp; }&lt;BR&gt;}&lt;/P&gt;
&lt;P&gt;typelib Food {&lt;BR&gt;&amp;nbsp; enum Cheese {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Green = 1&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Blue = 2&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Yellow = 3&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; White = 4&lt;BR&gt;&amp;nbsp; }&lt;BR&gt;}&lt;/P&gt;&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt;
&lt;P&gt;What does this VBScript program do if those type libraries have been added to the script engine namespace?&lt;/P&gt;&lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;
&lt;P&gt;foo.bar = Blue&lt;/P&gt;&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt;
&lt;P&gt;We've got a bit of a collision problem here. An obvious technique to solve this problem is to allow qualification:&lt;/P&gt;&lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;
&lt;P&gt;foo.bar = Color.Blue ' OK, it's 3 &lt;/P&gt;&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt;
&lt;P&gt;Which works great until we also add this type library:&lt;/P&gt;
&lt;P&gt;&lt;/P&gt;&lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;
&lt;P&gt;typelib Magic {&lt;BR&gt;&amp;nbsp; enum Color {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; White = 1&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Black = 2&lt;BR&gt;&amp;nbsp; }&lt;BR&gt;}&lt;/P&gt;&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt;
&lt;P&gt;Now it's not clear what &lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;foo.bar = Color.White&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt; means. We need two levels of disambiguation:&lt;/P&gt;&lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;
&lt;P&gt;foo.bar = Video.Color.White ' five&lt;/P&gt;&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt;
&lt;P&gt;Our major design decision here is to decide whether full qualification is a requirement &lt;B&gt;all the time&lt;/B&gt;, or &lt;B&gt;only when there is a collision&lt;/B&gt;. Or, somewhere in between; C# requires that enumerations be qualified by at least the type name but makes explicit full qualification optional via the "using" statement. C doesn't allow qualification at all -- you get a collision, that's your problem. (This is why you see so many enums in C that look like &lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;enum MagicColor { magicColorWhite, magicColorBlack };&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt; in an attempt to avoid collisions.&lt;/P&gt;
&lt;P&gt;We gave this a lot of thought and decided that the likely scenario was that collisions would be rare. Therefore users should not be forced to always qualify their enumerations at either the enumeration or library level. However, since collisions &lt;I&gt;might&lt;/I&gt; occur, we should not act like C. In short, &lt;B&gt;full, partial and no qualification should all be legal&lt;/B&gt;.&lt;/P&gt;
&lt;P&gt;There are other design constraints that might not be immediately obvious. For example, &lt;B&gt;full qualification must always work even in a world where type information is not known at compile time&lt;/B&gt;. Suppose you have the three type libraries above plus&lt;/P&gt;&lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;
&lt;P&gt;typelib Cheese {&lt;BR&gt;&amp;nbsp; enum Blue{&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Stilton = 1&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Gorgonzola = 2&lt;BR&gt;&amp;nbsp; }&lt;BR&gt;}&lt;/P&gt;&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt;
&lt;P&gt;The code &lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;foo.bar = Cheese.Blue.Stilton &lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt;must succeed -- we can't decide&amp;nbsp;at runtime that this really means the nonsensical&amp;nbsp;&lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;Food.Cheese.Blue.Stilton &lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt;and raise an error.&amp;nbsp;But we cannot do any analysis before the code runs either, because for all we know, someone used &lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;Execute&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt; to introduce a local object variable called &lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;Cheese&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt;, which would then win over either of those options. Furthermore, we might not even have the type libraries available when the compiler runs: the host can choose to add them after the script has been compiled. (Though that would be irksome, it is legal.) We can't make any assumptions at code generation time -- we have to assume that this is a series of object property calls like any other.&lt;/P&gt;
&lt;P&gt;Next time we'll revisit how the script engines handle host-supplied objects, and see how that mechanism neatly solves our design problem. Then we'll see why this isn't fast compared to declaring the constant yourself.&lt;/P&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=430881" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/ericlippert/archive/tags/JScript/default.aspx">JScript</category><category domain="http://blogs.msdn.com/ericlippert/archive/tags/VBScript/default.aspx">VBScript</category><category domain="http://blogs.msdn.com/ericlippert/archive/tags/Scripting/default.aspx">Scripting</category><category domain="http://blogs.msdn.com/ericlippert/archive/tags/Performance/default.aspx">Performance</category></item><item><title>Bad Recursion Revisited</title><link>http://blogs.msdn.com/ericlippert/archive/2005/04/28/bad-recursion-revisited.aspx</link><pubDate>Thu, 28 Apr 2005 21:12:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:413061</guid><dc:creator>Eric Lippert</dc:creator><slash:comments>22</slash:comments><comments>http://blogs.msdn.com/ericlippert/comments/413061.aspx</comments><wfw:commentRss>http://blogs.msdn.com/ericlippert/commentrss.aspx?PostID=413061</wfw:commentRss><description>&lt;FONT face="lucida sans unicode"&gt;&lt;FONT color=#800080 size=2&gt;
&lt;P&gt;We have internal email lists for questions about programming languages. Here's one that came across recently that I thought illustrated a good point about language design. &lt;/P&gt;
&lt;P&gt;An interview candidate gave the following awful implementation of the factorial function. (Recall that factorial is notated "n!", and is defined as the product of all the integers from 1 to n. 0! is defined as 1. So 4! = 4 x 3 x 2 x 1 = 24.)&lt;/P&gt;
&lt;P&gt;If you note that n! = n x ((n-1)!) then a &lt;/FONT&gt;&lt;a href="http://blogs.msdn.com/ericlippert/archive/2004/05/19/135392.aspx"&gt;&lt;U&gt;&lt;FONT color=#0000ff size=2&gt;recursive solution&lt;/U&gt;&lt;/FONT&gt;&lt;/A&gt;&lt;FONT color=#800080 size=2&gt; comes to mind. When asked to implement the factorial function in C, an interview candidate came up with this:&lt;/P&gt;&lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;
&lt;P&gt;int F(int x){&lt;BR&gt;&amp;nbsp; return (x &amp;gt; 1) ? (x * F(--x)) : x;&lt;BR&gt;}&lt;/P&gt;&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt;
&lt;P&gt;Now, leaving aside for the moment the fact that &lt;/FONT&gt;&lt;a href="http://blogs.msdn.com/ericlippert/archive/2004/5/20.aspx"&gt;&lt;U&gt;&lt;FONT color=#0000ff size=2&gt;this&amp;nbsp;badly-named function&amp;nbsp;does no bounds checking on the inputs, potentially consumes the entire stack, returns a wrong or nonsensical answer for inputs less than one, and is a recursive solution to a problem that can easily be solved with a simple lookup table&lt;/U&gt;&lt;/FONT&gt;&lt;/A&gt;&lt;FONT color=#800080 size=2&gt;, it has another big problem -- it doesn't even return the correct answer for any input greater than one either! F(4) will return 6, not 24, in Microsoft C. &lt;/P&gt;
&lt;P&gt;And yet the &lt;I&gt;seemingly&lt;/I&gt; equivalent C#, JScript and VBScript programs return 24.&lt;/P&gt;
&lt;P&gt;The question was "What the heck is up with that?" &lt;/P&gt;
&lt;P&gt;This looks perfectly straightforward. If x is 4, then we evaluate the consequence of the trinary operator. 4 * F(3) = 4 * 3 * F(2) = 4 * 3 * 2 * F(1) = 4 * 3 * 2 * 1 = 24, right? What is broken with C?&lt;/P&gt;
&lt;P&gt;Page 52 of K&amp;amp;R has the answer.&lt;/P&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;
&lt;P&gt;"C, like most languages, does not specify the order in which the operands of an operator are evaluated. (The exceptions are &amp;amp;&amp;amp;, ||, ?: and ','.) For example, in a statement like x = f()+g(); f may be evaluated before g or vice versa; thus if either f or g alters a variable on which the other depends, x can depend on the order of evaluation."&lt;/P&gt;&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt;
&lt;P&gt;The Microsoft C compiler actually evaluates the function call first, which causes x to be decremented &lt;I&gt;before&lt;/I&gt; the multiplication. So this is actually the same as 3 * F(3) = 3 * 2 * F(1) = 3 * 2 * 1 = 6.&lt;/P&gt;
&lt;P&gt;Why does the specification call out that the compiler can choose any order for subexpression evaluation? Because then the compiler can choose to optimize the order so that it consumes a small number of stack or register slots for the results. &lt;/P&gt;
&lt;P&gt;Of course, C&amp;nbsp;was written back in the dark ages --&amp;nbsp;the 1970's&amp;nbsp;-- when indeed most languages were pretty ill-specified and full of terrible "gotchas" like this. JScript, VBScript, C#, and most modern languages do guarantee that functions will be evaluated in left-to-right order. In all these languages, &lt;/P&gt;
&lt;P&gt;&lt;FONT color=#000080&gt;x = f() + g() * h();&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;will evaluate f, then g, then h.&lt;/P&gt;
&lt;P&gt;As K&amp;amp;R notes &lt;FONT color=#000000&gt;"The moral is that writing code that depends on order of evaluations is a bad programming practice in any language."&lt;/FONT&gt;&amp;nbsp; Amen to that!&lt;/P&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=413061" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/ericlippert/archive/tags/JScript/default.aspx">JScript</category><category domain="http://blogs.msdn.com/ericlippert/archive/tags/VBScript/default.aspx">VBScript</category><category domain="http://blogs.msdn.com/ericlippert/archive/tags/Scripting/default.aspx">Scripting</category><category domain="http://blogs.msdn.com/ericlippert/archive/tags/C_2300_/default.aspx">C#</category><category domain="http://blogs.msdn.com/ericlippert/archive/tags/Code+Quality/default.aspx">Code Quality</category><category domain="http://blogs.msdn.com/ericlippert/archive/tags/Recursion/default.aspx">Recursion</category><category domain="http://blogs.msdn.com/ericlippert/archive/tags/precedence/default.aspx">precedence</category></item><item><title>How Do Script Engines Implement Object Identity?</title><link>http://blogs.msdn.com/ericlippert/archive/2005/04/26/412199.aspx</link><pubDate>Tue, 26 Apr 2005 21:49:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:412199</guid><dc:creator>Eric Lippert</dc:creator><slash:comments>7</slash:comments><comments>http://blogs.msdn.com/ericlippert/comments/412199.aspx</comments><wfw:commentRss>http://blogs.msdn.com/ericlippert/commentrss.aspx?PostID=412199</wfw:commentRss><description>&lt;FONT face="lucida sans unicode"&gt;&lt;FONT color=#800080 size=2&gt;
&lt;P&gt;I've talked a few times in this blog about the semantics of the equality operators in various languages. (Such as &lt;/FONT&gt;&lt;a href="http://blogs.msdn.com/ericlippert/archive/2004/07/26/197302.aspx"&gt;&lt;U&gt;&lt;FONT color=#0000ff size=2&gt;here&lt;/U&gt;&lt;/FONT&gt;&lt;/A&gt;&lt;FONT color=#800080 size=2&gt;, and &lt;/FONT&gt;&lt;a href="http://blogs.msdn.com/ericlippert/archive/2004/07/30/202432.aspx"&gt;&lt;U&gt;&lt;FONT color=#0000ff size=2&gt;here&lt;/U&gt;&lt;/FONT&gt;&lt;/A&gt;&lt;FONT color=#800080 size=2&gt;.) Recently a reader asked me how JScript &lt;I&gt;implements&lt;/I&gt; object identity. That is, given two objects, how do we know if they are "the same object" or not? &lt;/P&gt;
&lt;P&gt;For the remainder of this discussion I'm going to assume that we've got two non-null objects that we're comparing for identity. The details of how objects are compared to strings, numbers, etc, will have to wait for another blog entry.&lt;/P&gt;
&lt;P&gt;Note also that in VBScript, the comparison operator for objects is &lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;Is&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt;, not &lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;=.&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt; Also, &lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;==&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt; and &lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;===&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt; in JScript behave identically if both arguments are objects; essentially the implementation of &lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;Is&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt;, &lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;==&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt; and &lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;===&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt; are all the same as far as object comparison goes.&lt;/P&gt;
&lt;P&gt;Behind the scenes, everything in a VBScript/JScript program is represented as a variant. Most of the time, variants containing objects will have their variant type field set to VT_DISPATCH, and their pdispVal field set with a pointer to the object. (Occasionally we'll have a VT_UNKNOWN with a punkVal field instead, but lets ignore that corner case for now.) Suppose we want to compare two such objects for equality. We could pass the pdispVal of each to a helper function and compare the pointers.&lt;/P&gt;&lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;
&lt;P&gt;bool AreObjectsEqual(IDispatch * pdisp1, IDispatch * pdisp2)&lt;BR&gt;{&lt;BR&gt;&amp;nbsp; if (pdisp1 == pdisp2)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return true;&lt;BR&gt;&amp;nbsp;&amp;nbsp;return false;&lt;BR&gt;}&lt;/P&gt;&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt;
&lt;P&gt;And we're done. Wow, that was easy.&lt;/P&gt;
&lt;P&gt;Except that it's wrong. In VBScript, those objects could be two different dispatch pointers to the same object because &lt;/FONT&gt;&lt;a href="http://blogs.msdn.com/ericlippert/archive/2003/10/10/53188.aspx"&gt;&lt;U&gt;&lt;FONT color=#0000ff size=2&gt;VBScript supports non-default dispatches&lt;/U&gt;&lt;/FONT&gt;&lt;/A&gt;&lt;FONT color=#800080 size=2&gt;. JScript does not support non-default dispatches, but in JScript there are also situations in which you can have two different dispatch pointers to the same object; we'll come to that later.&lt;/P&gt;
&lt;P&gt;If its not clear why the two pointers to the same object could be numerically different, read &lt;/FONT&gt;&lt;a href="http://blogs.msdn.com/oldnewthing/archive/2004/02/05/68017.aspx"&gt;&lt;U&gt;&lt;FONT color=#0000ff size=2&gt;Raymond's article on how COM objects are laid out in memory&lt;/U&gt;&lt;/FONT&gt;&lt;/A&gt;&lt;FONT color=#800080 size=2&gt;, and you'll see why. There can be many dispatch vtables.&lt;/P&gt;
&lt;P&gt;How can we ever determine when two COM objects are the same? We have to rely upon one of the most important rules of COM: if an object multiply inherits &lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;IUnknown&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt; then calling &lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;QueryInterface&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt; for &lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;IUnknown&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt; on &lt;I&gt;any&lt;/I&gt; of those implementations must &lt;I&gt;always&lt;/I&gt; give back the same pointer. As you can see in Raymond's example of multiple inheritance, there are two &lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;IUnknown&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt; vtables. It is illegal for each of them to return a pointer to itself when QI'd for &lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;IUnknown&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt;; the implementation must consistently pick one of them every time.&lt;/P&gt;
&lt;P&gt;So now it's pretty clear what we must do:&lt;/P&gt;&lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;
&lt;P&gt;bool AreObjectsEqual(IDispatch * pdisp1, IDispatch * pdisp2)&lt;BR&gt;{&lt;BR&gt;&amp;nbsp; IUnknown * punk1 = NULL;&lt;BR&gt;&amp;nbsp; IUnknown * punk2 = NULL;&lt;BR&gt;&amp;nbsp; if (pdisp1 == pdisp2)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return true;&lt;BR&gt;&amp;nbsp; if (pdisp1 == NULL || pdisp2 == NULL)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return false;&lt;BR&gt;&amp;nbsp; pdisp1-&amp;gt;QueryInterface(IID_IUnknown, (void**)&amp;amp;punk1);&lt;BR&gt;&amp;nbsp; pdisp2-&amp;gt;QueryInterface(IID_IUnknown, (void**)&amp;amp;punk2);&lt;BR&gt;&amp;nbsp; // This should never fail, but better safe than sorry.&lt;BR&gt;&amp;nbsp; if (punk1 != NULL)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; punk1-&amp;gt;Release();&lt;BR&gt;&amp;nbsp; if (punk2 != NULL)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; punk2-&amp;gt;Release();&lt;BR&gt;&amp;nbsp; // We're not dereferencing the pointers, so it is OK to use the&lt;BR&gt;&amp;nbsp;&amp;nbsp;// locals even after their release.&lt;BR&gt;&amp;nbsp; if (punk1 == punk2)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return true;&lt;BR&gt;&amp;nbsp; return false;&lt;BR&gt;}&lt;/P&gt;&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt;
&lt;P&gt;Unfortunately, that's not the whole story either. &lt;/P&gt;
&lt;P&gt;For security reasons, Internet Explorer sometimes creates proxy objects -- little objects that detect if they are being used safely, and if they are, then they forward the call to the real implementation, on a separate object. You can run into situations in IE where you have two proxy objects to the same "real" object -- as far as COM is concerned, all three are different objects, but as far as IE is concerned, that's an implementation detail of the security system which we would like to hide from the script users.&lt;/P&gt;
&lt;P&gt;To solve this problem, IE implements a special interface that knows when two IUnknown objects are both proxies for the same object. The script engines actually do something like this:&lt;/P&gt;&lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;
&lt;P&gt;bool AreObjectsEqual(IDispatch * pdisp1, IDispatch * pdisp2) {&lt;BR&gt;&amp;nbsp; IUnknown * punk1 = NULL;&lt;BR&gt;&amp;nbsp; IUnknown * punk2 = NULL;&lt;BR&gt;&amp;nbsp; IObjectIdentity * pObjectIdentity;&lt;BR&gt;&amp;nbsp; bool fRet = false;&lt;BR&gt;&amp;nbsp; HRESULT hr;&lt;BR&gt;&amp;nbsp; if (pdisp1 == pdisp2)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; fRet = true;&lt;BR&gt;&amp;nbsp; else if (pdisp1 != NULL &amp;amp;&amp;amp; pdisp2 != NULL) {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; // This must always succeed.&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; pdisp1-&amp;gt;QueryInterface(IID_IUnknown, (void**)&amp;amp;punk1);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; pdisp2-&amp;gt;QueryInterface(IID_IUnknown, (void**)&amp;amp;punk2);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (punk1 == punk2)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; fRet = true;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; else if (punk1 != NULL &amp;amp;&amp;amp; punk2 != NULL) {&amp;nbsp;// This should never be false.&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; hr = punk1-&amp;gt;QueryInterface(IID_IObjectIdentity, (void **)&amp;amp;pObjectIdentity);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (SUCCEEDED(hr)) &amp;amp;&amp;amp; pObjectIdentity != NULL) {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; hr = pObjectIdentity-&amp;gt;IsEqualObject(punk2);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (hr == S_OK)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; fRet = true;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;&amp;nbsp; }&lt;BR&gt;&amp;nbsp; if (pObjectIdentity != NULL)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; pObjectIdentity-&amp;gt;Release();&lt;BR&gt;&amp;nbsp; if (punk1 != NULL)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; punk1-&amp;gt;Release();&lt;BR&gt;&amp;nbsp; if (punk2 != NULL)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; punk2-&amp;gt;Release();&lt;BR&gt;&amp;nbsp; return fRet;&lt;BR&gt;}&lt;/P&gt;&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt;
&lt;P&gt;Which is a heck of a lot of code just to determine if two pointers are equal, but that's the tax you pay for object-oriented programming. Of course, you don't need to do any of this rigamarole with &lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;IObjectIdentity&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt; unless you're writing code that messes around with IE objects.&lt;/P&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=412199" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/ericlippert/archive/tags/JScript/default.aspx">JScript</category><category domain="http://blogs.msdn.com/ericlippert/archive/tags/VBScript/default.aspx">VBScript</category><category domain="http://blogs.msdn.com/ericlippert/archive/tags/Scripting/default.aspx">Scripting</category><category domain="http://blogs.msdn.com/ericlippert/archive/tags/COM+Programming/default.aspx">COM Programming</category></item><item><title>Binary Files and the File System Object Do Not Mix</title><link>http://blogs.msdn.com/ericlippert/archive/2005/04/20/binary-files-and-the-file-system-object-do-not-mix.aspx</link><pubDate>Wed, 20 Apr 2005 21:47:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:410127</guid><dc:creator>Eric Lippert</dc:creator><slash:comments>32</slash:comments><comments>http://blogs.msdn.com/ericlippert/comments/410127.aspx</comments><wfw:commentRss>http://blogs.msdn.com/ericlippert/commentrss.aspx?PostID=410127</wfw:commentRss><description>&lt;FONT face="lucida sans unicode"&gt;&lt;FONT color=#800080 size=2&gt;
&lt;P&gt;OK, back to scripting today.&lt;/P&gt;
&lt;P&gt;But before I get back to scripting issues, one brief correction. An attentive reader noted that "The Well-Tempered Clavier" was in fact designed to sound good on a "well tempered" instrument, not an "equally tempered" instrument. The difference is that a "well" temperament is designed so that every key sounds good, but is allowed to have some badly-out-of-tune intervals that must be avoided. (Traditionally these are called "wolf intervals".) &lt;/P&gt;
&lt;P&gt;There was considerable controversy when equal temperament was introduced in Europe. I suppose it was the "what is the One True Bracing Style?" ridiculous issue of the day.&lt;/P&gt;
&lt;P&gt;&lt;/P&gt;
&lt;P&gt;Another commenter pointed out that you could translate my wav-writing program into VBScript by using the File System Object to write out the bytes. To simplify their code down to a program that writes out individual bytes:&lt;/P&gt;
&lt;P&gt;&lt;/P&gt;&lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;
&lt;P&gt;' DO NOT DO THIS&lt;BR&gt;Set FSO=CreateObject("Scripting.FileSystemObject") &lt;BR&gt;Set File=FSO.CreateTextFile("c:\test.bin", True) &lt;BR&gt;For i = 0 to 255&lt;BR&gt;&amp;nbsp; File.Write Chr(i) &lt;BR&gt;Next&lt;BR&gt;File.Close&lt;/P&gt;&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt;
&lt;P&gt;&lt;/P&gt;
&lt;P&gt;And sure enough, this writes out a binary file consisting of those bytes. &lt;/P&gt;
&lt;P&gt;&lt;/P&gt;
&lt;P&gt;Please don't do that. See that line that says "CreateTextFile"? We wrote that method to &lt;STRONG&gt;create a text file&lt;/STRONG&gt;, not a binary file. Though this code might appear to work, it actually does not. Text files are more than just binary files that can be interpreted as text. Text files have to conform to certain rules to ensure that they can be sensibly interpreted as text in the local code page. If that's not 100% clear to you, read &lt;A href="http://www.joelonsoftware.com/articles/Unicode.html"&gt;Joel's article on the subject &lt;/A&gt;before we go on.&lt;/P&gt;
&lt;P&gt;&lt;/P&gt;
&lt;P&gt;Let me give you an example that &lt;EM&gt;clearly&lt;/EM&gt; fails. What does this program do?&lt;/P&gt;
&lt;P&gt;&lt;/P&gt;&lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;
&lt;P&gt;Set FSO=CreateObject("Scripting.FileSystemObject") &lt;BR&gt;Set File=FSO.CreateTextFile("c:\test.bin", True) &lt;BR&gt;For i = 0 to 255&lt;BR&gt;&amp;nbsp; File.Write Chr(&amp;amp;hE0) &lt;BR&gt;Next&lt;BR&gt;File.Close&lt;/P&gt;&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt;
&lt;P&gt;&lt;/P&gt;
&lt;P&gt;If you said "it writes out a binary file consisting of 256 E0 bytes," bzzt! Sorry, try again. The correct answer is "it writes out a binary file consisting of 256 E0 bytes on any operating system where the user's default ANSI code page does not define E0 as a lead byte in a DBCS encoding, like, say, Japanese, in which case it&amp;nbsp;writes out 256 zeros." &lt;/P&gt;
&lt;P&gt;In the Japanese code page, just-plain-chr(E0) is &lt;STRONG&gt;not even a legal character&lt;/STRONG&gt;, so &lt;FONT color=#000080&gt;Chr&lt;/FONT&gt; will turn it into a zero.&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;/P&gt;
&lt;P&gt;If I were whipping up a little one-off program on my own to write out a binary file -- well, I'd personally do it in C, but I can see how some people might want to do it in script. But there's a big difference between writing a one-off program that you're going to delete in five minutes, and writing a general-purpose utility program that you expect people around the world will use. That's an entirely&amp;nbsp;different standard of robustness and portability. &lt;STRONG&gt;Do not use the FSO to read/write binary files, you're just asking for a world of hurt as soon as someone in DBCS-land runs your code.&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;&lt;/P&gt;
&lt;P&gt;I have been asked many times over the years if I know of a scriptable object that can read-write true binary files in all locales. I do not. Anyone have any suggestions? I would have thought given the number of people that have asked me, that some third party would have come up with something decent by now.&lt;/P&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=410127" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/ericlippert/archive/tags/VBScript/default.aspx">VBScript</category><category domain="http://blogs.msdn.com/ericlippert/archive/tags/Scripting/default.aspx">Scripting</category><category domain="http://blogs.msdn.com/ericlippert/archive/tags/Code+Quality/default.aspx">Code Quality</category></item><item><title>VBScript Quiz Answers, Parts Eleven and Twelve</title><link>http://blogs.msdn.com/ericlippert/archive/2005/04/05/vbscript-quiz-answers-parts-eleven-and-twelve.aspx</link><pubDate>Tue, 05 Apr 2005 21:25:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:405602</guid><dc:creator>Eric Lippert</dc:creator><slash:comments>7</slash:comments><comments>http://blogs.msdn.com/ericlippert/comments/405602.aspx</comments><wfw:commentRss>http://blogs.msdn.com/ericlippert/commentrss.aspx?PostID=405602</wfw:commentRss><description>&lt;FONT face="Lucida Sans Unicode" size=2&gt;
&lt;P&gt;11)&lt;/FONT&gt; &lt;FONT face="Lucida Console" color=#000080 size=2&gt;X&lt;/FONT&gt;&lt;FONT face="Lucida Sans Unicode" size=2&gt; and&lt;/FONT&gt; &lt;FONT face="Lucida Console" color=#000080 size=2&gt;Y&lt;/FONT&gt;&lt;FONT face="Lucida Sans Unicode" size=2&gt; are both Booleans.&amp;nbsp; Which of the following always assigns&lt;/FONT&gt; &lt;FONT face="Lucida Console" color=#000080 size=2&gt;True&lt;/FONT&gt;&lt;FONT face="Lucida Sans Unicode" size=2&gt;?&amp;nbsp; Why?&lt;/P&gt;&lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#800080 size=2&gt;
&lt;P&gt;(a)&lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#000080 size=2&gt; Z = Not X Or Y = X Imp Y&lt;BR&gt;&lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#800080 size=2&gt;(b)&lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#000080 size=2&gt; Z = X Imp Y = Not X Or Y&lt;BR&gt;&lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#800080 size=2&gt;(c)&lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#000080 size=2&gt; Z = X Eqv Y = Not X XOr Y&lt;BR&gt;&lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#800080 size=2&gt;(d)&lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#000080 size=2&gt; Z = Not X XOr Y = X Eqv Y&amp;nbsp; &lt;/P&gt;&lt;/FONT&gt;&lt;FONT face="Lucida Sans Unicode" color=#800080 size=2&gt;
&lt;P&gt;(a) assigns&lt;/FONT&gt; &lt;FONT face="Lucida Console" color=#000080 size=2&gt;False&lt;/FONT&gt;&lt;FONT face="Lucida Sans Unicode" color=#800080 size=2&gt; if&lt;/FONT&gt; &lt;FONT face="Lucida Console" color=#000080 size=2&gt;X&lt;/FONT&gt;&lt;FONT face="Lucida Sans Unicode" color=#800080 size=2&gt; and&lt;/FONT&gt; &lt;FONT face="Lucida Console" color=#000080 size=2&gt;Y&lt;/FONT&gt;&lt;FONT face="Lucida Sans Unicode" color=#800080 size=2&gt; are both&lt;/FONT&gt; &lt;FONT face="Lucida Console" color=#000080 size=2&gt;False&lt;/FONT&gt;&lt;FONT face="Lucida Sans Unicode" color=#800080 size=2&gt;.&amp;nbsp; The others assign&lt;/FONT&gt; &lt;FONT face="Lucida Console" color=#000080 size=2&gt;True&lt;/FONT&gt;&lt;FONT face="Lucida Sans Unicode" color=#800080 size=2&gt; no matter what&lt;/FONT&gt; &lt;FONT face="Lucida Console" color=#000080 size=2&gt;X&lt;/FONT&gt;&lt;FONT face="Lucida Sans Unicode" color=#800080 size=2&gt; and&lt;/FONT&gt; &lt;FONT face="Lucida Console" color=#000080 size=2&gt;Y&lt;/FONT&gt;&lt;FONT face="Lucida Sans Unicode" color=#800080 size=2&gt; are. However, these are not as straightforward as you might think.&lt;/P&gt;&lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#000080 size=2&gt;
&lt;P&gt;Imp&lt;/FONT&gt;&lt;FONT face="Lucida Sans Unicode" color=#800080 size=2&gt; is the "logical implication" operator.&lt;/FONT&gt; &lt;FONT face="Lucida Console" color=#000080 size=2&gt;X&lt;/FONT&gt; &lt;FONT face="Lucida Console" color=#000080 size=2&gt;Imp&lt;/FONT&gt; &lt;FONT face="Lucida Console" color=#000080 size=2&gt;Y&lt;/FONT&gt;&lt;FONT face="Lucida Sans Unicode" color=#800080 size=2&gt; means "If&lt;/FONT&gt; &lt;FONT face="Lucida Console" color=#000080 size=2&gt;X&lt;/FONT&gt;&lt;FONT face="Lucida Sans Unicode" color=#800080 size=2&gt; is&lt;/FONT&gt; &lt;FONT face="Lucida Console" color=#000080 size=2&gt;True&lt;/FONT&gt;&lt;FONT face="Lucida Sans Unicode" color=#800080 size=2&gt; then&lt;/FONT&gt; &lt;FONT face="Lucida Console" color=#000080 size=2&gt;Y&lt;/FONT&gt;&lt;FONT face="Lucida Sans Unicode" color=#800080 size=2&gt; is&lt;/FONT&gt; &lt;FONT face="Lucida Console" color=#000080 size=2&gt;True&lt;/FONT&gt;&lt;FONT face="Lucida Sans Unicode" color=#800080 size=2&gt;". It is always&lt;/FONT&gt; &lt;FONT face="Lucida Console" color=#000080 size=2&gt;True&lt;/FONT&gt;&lt;FONT face="Lucida Sans Unicode" color=#800080 size=2&gt; unless&lt;/FONT&gt; &lt;FONT face="Lucida Console" color=#000080 size=2&gt;X&lt;/FONT&gt;&lt;FONT face="Lucida Sans Unicode" color=#800080 size=2&gt; is&lt;/FONT&gt; &lt;FONT face="Lucida Console" color=#000080 size=2&gt;True&lt;/FONT&gt;&lt;FONT face="Lucida Sans Unicode" color=#800080 size=2&gt; and&lt;/FONT&gt; &lt;FONT face="Lucida Console" color=#000080 size=2&gt;Y&lt;/FONT&gt;&lt;FONT face="Lucida Sans Unicode" color=#800080 size=2&gt; is&lt;/FONT&gt; &lt;FONT face="Lucida Console" color=#000080 size=2&gt;False&lt;/FONT&gt;&lt;FONT face="Lucida Sans Unicode" color=#800080 size=2&gt;.&lt;/FONT&gt; &lt;/P&gt;&lt;FONT face="Lucida Console" color=#000080 size=2&gt;
&lt;P&gt;Eqv&lt;/FONT&gt;&lt;FONT face="Lucida Sans Unicode" color=#800080 size=2&gt; is the "logical equivalence" operator.&lt;/FONT&gt; &lt;FONT face="Lucida Console" color=#000080 size=2&gt;X Eqv Y&lt;/FONT&gt; &lt;FONT face="Lucida Sans Unicode" color=#800080 size=2&gt;is&lt;/FONT&gt; &lt;FONT face="Lucida Console" color=#000080 size=2&gt;True&lt;/FONT&gt;&lt;FONT face="Lucida Sans Unicode" color=#800080 size=2&gt; if&lt;/FONT&gt; &lt;FONT face="Lucida Console" color=#000080 size=2&gt;X&lt;/FONT&gt;&lt;FONT face="Lucida Sans Unicode" color=#800080 size=2&gt; and&lt;/FONT&gt; &lt;FONT face="Lucida Console" color=#000080 size=2&gt;Y&lt;/FONT&gt;&lt;FONT face="Lucida Sans Unicode" color=#800080 size=2&gt; are both&lt;/FONT&gt; &lt;FONT face="Lucida Console" color=#000080 size=2&gt;True&lt;/FONT&gt;&lt;FONT face="Lucida Sans Unicode" color=#800080 size=2&gt; or both&lt;/FONT&gt; &lt;FONT face="Lucida Console" color=#000080 size=2&gt;False&lt;/FONT&gt;&lt;FONT face="Lucida Sans Unicode" color=#800080 size=2&gt;.&lt;/P&gt;
&lt;P&gt;Why do we need &lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#000080 size=2&gt;Eqv&lt;/FONT&gt;&lt;FONT face="Lucida Sans Unicode" color=#800080 size=2&gt; -- isn't that the definition of "equals"?&amp;nbsp; The difference is that if given numbers instead of Booleans, these do the same logic on corresponding pairs of bits.&lt;/P&gt;
&lt;P&gt;If two logical expressions are always equal no matter what the values of their variables are, then they are logically identical. Such a relationship is called an "identity".&amp;nbsp; These are clearly identities:&lt;/P&gt;&lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#800080 size=2&gt;
&lt;P&gt;(a)&lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#000080 size=2&gt; Z = ((Not X) Or Y) = (X Imp Y)&lt;BR&gt;&lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#800080 size=2&gt;(b)&lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#000080 size=2&gt; Z = (X Imp Y) = ((Not X) Or Y)&lt;BR&gt;&lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#800080 size=2&gt;(c)&lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#000080 size=2&gt; Z = (X Eqv Y) = (Not (X XOr Y))&lt;BR&gt;&lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#800080 size=2&gt;(d)&lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#000080 size=2&gt; Z = (Not (X XOr Y)) = (X Eqv Y)&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/P&gt;&lt;/FONT&gt;&lt;FONT face="Lucida Sans Unicode" color=#800080 size=2&gt;
&lt;P&gt;No matter what Boolean values X and Y are, Z will always be True.&amp;nbsp; The trick here though is the operator precedence. Just like 1 + 2 * 3 is 7, not 9, these guys all have precedence.&amp;nbsp; To show the precedence with brackets, the expressions I actually asked about are equivalent to&lt;/P&gt;&lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#800080 size=2&gt;
&lt;P&gt;(a)&lt;/FONT&gt; &lt;FONT face="Lucida Console" color=#000080 size=2&gt;Z = (((Not X) Or (Y = X)) Imp Y)&lt;BR&gt;&lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#800080 size=2&gt;(b)&lt;/FONT&gt; &lt;FONT face="Lucida Console" color=#000080 size=2&gt;Z = (X Imp ((Y = (Not X)) Or Y))&lt;BR&gt;&lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#800080 size=2&gt;(c)&lt;/FONT&gt; &lt;FONT face="Lucida Console" color=#000080 size=2&gt;Z = (X Eqv ((Y = (Not X)) XOr Y))&lt;BR&gt;&lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#800080 size=2&gt;(d)&lt;/FONT&gt; &lt;FONT face="Lucida Console" color=#000080 size=2&gt;Z = (((Not X) XOr (Y = X)) Eqv Y)&lt;/P&gt;&lt;/FONT&gt;&lt;FONT face="Lucida Sans Unicode" color=#800080 size=2&gt;
&lt;P&gt;It is much less clear now that the last three are identities. The moral of the story is to be very careful with operator precedence when using logical operators -- equals binds tighter than &lt;FONT color=#000080&gt;Or&lt;/FONT&gt;!&lt;/P&gt;&lt;/FONT&gt;&lt;FONT face="Lucida Sans Unicode" size=2&gt;
&lt;P&gt;12) Consider this program:&lt;/P&gt;&lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#000080 size=2&gt;
&lt;P&gt;s = "Eric read Æsop's Fables"&lt;BR&gt;arr = Split(s, "e", -1, 1)&lt;/P&gt;&lt;/FONT&gt;&lt;FONT face="Lucida Sans Unicode" color=#800080 size=2&gt;
&lt;P&gt;arr is an array with how many elements?&lt;/P&gt;
&lt;P&gt;(a) 2&lt;BR&gt;(b) 3&lt;BR&gt;(c) 4&lt;BR&gt;(d) 5&lt;/P&gt;
&lt;P&gt;It's (c).&amp;nbsp; The parts are "", "ric r", "ad Æsop's Fabl", "s"&lt;/P&gt;
&lt;P&gt;The&amp;nbsp;1 means "go case insensitive". I agonized over whether or not &lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#000080 size=2&gt;Split&lt;/FONT&gt;&lt;FONT face="Lucida Sans Unicode" color=#800080 size=2&gt; should&amp;nbsp;split on matches to ligature characters. It gave me grief because this &lt;I&gt;does&lt;/I&gt; work:&lt;/P&gt;
&lt;P&gt;&lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#000080 size=2&gt;print Instr(1, "xxxÆxxx", "e", 1)&lt;/P&gt;&lt;/FONT&gt;&lt;FONT face="Lucida Sans Unicode" color=#800080 size=2&gt;
&lt;P&gt;That finds the "e" inside the ligature, so why shouldn't &lt;FONT color=#000080&gt;Split&lt;/FONT&gt; split on the ligature? Basically, we just decided that it was &lt;EM&gt;too weird&lt;/EM&gt; to split a string in the middle of a ligature. I was never very happy with this decision, and if I had to do it again, I probably would decide the other way.&amp;nbsp; But it's too late now!&lt;/P&gt;
&lt;P&gt;Wow, that took longer than I expected.&amp;nbsp; Coming up next, a short break from scripting.&lt;/P&gt;&lt;/FONT&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=405602" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/ericlippert/archive/tags/VBScript/default.aspx">VBScript</category><category domain="http://blogs.msdn.com/ericlippert/archive/tags/Scripting/default.aspx">Scripting</category><category domain="http://blogs.msdn.com/ericlippert/archive/tags/Puzzles/default.aspx">Puzzles</category></item><item><title>VBScript Quiz Answers, Parts Nine and Ten</title><link>http://blogs.msdn.com/ericlippert/archive/2005/03/30/vbscript-quiz-answers-parts-nine-and-ten.aspx</link><pubDate>Wed, 30 Mar 2005 17:25:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:403799</guid><dc:creator>Eric Lippert</dc:creator><slash:comments>7</slash:comments><comments>http://blogs.msdn.com/ericlippert/comments/403799.aspx</comments><wfw:commentRss>http://blogs.msdn.com/ericlippert/commentrss.aspx?PostID=403799</wfw:commentRss><description>&lt;font face="lucida sans unicode"&gt;&lt;font size="2"&gt; &lt;p&gt;9) Which of these statements is syntactically legal?&amp;nbsp; Why?&lt;/p&gt;&lt;/font&gt;&lt;font face="Lucida Console" color="#800080" size="2"&gt; &lt;p&gt;(a)&lt;/font&gt; &lt;font face="Lucida Console" color="#000080" size="2"&gt;Const Z = -+-+-+-10&lt;br /&gt;&lt;/font&gt;&lt;font face="Lucida Console" color="#800080" size="2"&gt;(b)&lt;/font&gt; &lt;font face="Lucida Console" color="#000080" size="2"&gt;Const Y = 2 + 2&lt;br /&gt;&lt;/font&gt;&lt;font face="Lucida Console" color="#800080" size="2"&gt;(c)&lt;/font&gt; &lt;font face="Lucida Console" color="#000080" size="2"&gt;Const X = .1e310&lt;br /&gt;&lt;/font&gt;&lt;font face="Lucida Console" color="#800080" size="2"&gt;(d)&lt;/font&gt;&lt;font face="Lucida Console" color="#000080" size="2"&gt; Dim W(+10)&lt;/p&gt;&lt;/font&gt;&lt;font color="#800080" size="2"&gt; &lt;p&gt;(a) is legal. The rest are illegal.&lt;/p&gt; &lt;p&gt;(a) is legal because you can put as many unary positive or negative operators on top of a constant as you want, so long as it's a numeric constant.&lt;/font&gt; &lt;font color="#800080" size="2"&gt;(b) is illegal; as I've discussed &lt;/font&gt;&lt;A href="http://blogs.msdn.com/ericlippert/archive/2003/10/21/53264.aspx"&gt;&lt;u&gt;&lt;font color="#0000ff" size="2"&gt;before&lt;/u&gt;&lt;/font&gt;&lt;/a&gt;&lt;font color="#800080" size="2"&gt;, we do not support "constant folding" in VBScript.&lt;/font&gt; &lt;font color="#800080" size="2"&gt;(c) is illegal because it's outside the range of a float.&lt;/font&gt; &lt;font color="#800080" size="2"&gt;(d) is illegal because, bizarrely enough, dimension lists must be just straight integers, no operators whatsoever.&lt;/p&gt; &lt;p&gt;Clearly VBScript is inconsistent insofar as how unary operators and constants work together. These&amp;nbsp;inconsistencies are one&amp;nbsp;those unfortunate corner cases that got missed when the parser was designed.&lt;/p&gt;&lt;/font&gt;&lt;font size="2"&gt; &lt;p&gt;10) Which of these statements is syntactically legal?&amp;nbsp; Why?&lt;/p&gt;&lt;/font&gt;&lt;font face="Lucida Console" color="#800080" size="2"&gt; &lt;p&gt;(a)&lt;/font&gt;&lt;font face="Lucida Console" color="#000080" size="2"&gt; If Blah Then Foo Else Bar&lt;br /&gt;&lt;/font&gt;&lt;font face="Lucida Console" color="#800080" size="2"&gt;(b)&lt;/font&gt;&lt;font face="Lucida Console" color="#000080" size="2"&gt; If Blah Then If Foo Then Bar&lt;br /&gt;&lt;/font&gt;&lt;font face="Lucida Console" color="#800080" size="2"&gt;(c)&lt;/font&gt;&lt;font face="Lucida Console" color="#000080" size="2"&gt; If Blah Then Foo Bar Else Bar Foo&lt;br /&gt;&lt;/font&gt;&lt;font face="Lucida Console" color="#800080" size="2"&gt;(d)&lt;/font&gt;&lt;font face="Lucida Console" color="#000080" size="2"&gt; If Blah Then Foo Bar End If&lt;/p&gt;&lt;/font&gt;&lt;font color="#800080" size="2"&gt; &lt;p&gt;(a) is illegal, the rest are legal.&lt;/p&gt; &lt;p&gt;The VBScript single-line&lt;/font&gt; &lt;font face="Lucida Console" color="#000080" size="2"&gt;If&lt;/font&gt;&lt;font color="#800080" size="2"&gt;-statement parser is all screwed up. Again, some of these were bugs in the first version that we couldn't fix without breaking compatibility, and some are just plain bugs that never got fixed for no particular reason.&lt;/p&gt; &lt;p&gt;(b) is perfectly legal, nothing odd here.&lt;/font&gt;&lt;/p&gt;&lt;font color="#800080" size="2"&gt; &lt;p&gt;(a) is legal in VB6 but not in VBScript because of a mistake.&amp;nbsp;The parser sees IF ID THEN ID ELSE... and tries to parse "ID ELSE" as a statement. The statement processor&lt;/font&gt; &lt;font color="#800080" size="2"&gt;(correctly)&lt;/font&gt; &lt;font color="#800080" size="2"&gt;thinks that the id is a procedure call and it tries to parse the argument list. The argument list processor should detect the&lt;/font&gt; &lt;font face="Lucida Console" color="#000080" size="2"&gt;Else&lt;/font&gt;&lt;font color="#800080" size="2"&gt; and figure oh, I'm in an&lt;/font&gt; &lt;font face="Lucida Console" color="#000080" size="2"&gt;If&lt;/font&gt;&lt;font color="#800080" size="2"&gt; and the statement is done, but it doesn't figure that out, it just creates a syntax error.&lt;/font&gt; &lt;font color="#800080" size="2"&gt;(c) is legal because in this case the argument list parser finds an argument list before the &lt;/font&gt;&lt;font face="Lucida Console" color="#000080" size="2"&gt;Else&lt;/font&gt;&lt;font color="#800080" size="2"&gt; and doesn't freak out.&lt;/font&gt; &lt;/p&gt;&lt;font color="#800080" size="2"&gt; &lt;p&gt;A number of people pointed out that having both &lt;/font&gt;&lt;font face="Lucida Console" color="#000080" size="2"&gt;Foo Bar &lt;/font&gt;&lt;font color="#800080" size="2"&gt;and&lt;/font&gt;&lt;font face="Lucida Console" color="#000080" size="2"&gt; Bar Foo &lt;/font&gt;&lt;font color="#800080" size="2"&gt;in the same program is a little weird. Yes, it is! But the question was what is &lt;i&gt;syntactically&lt;/i&gt; legal, not what makes sense. And in fact, it is possible for this to work:&lt;/p&gt;&lt;/font&gt;&lt;font face="Lucida Console" color="#000080" size="2"&gt; &lt;p&gt;Class ABC&lt;br /&gt;&amp;nbsp; Public Default Sub DEF(X)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Msgbox X.Name&lt;br /&gt;&amp;nbsp; End Sub&lt;br /&gt;&amp;nbsp; Public Name&lt;br /&gt;End Class&lt;br /&gt;Set Foo = New ABC&lt;br /&gt;Foo.Name = "Foo"&lt;br /&gt;Set Bar = New ABC&lt;br /&gt;Bar.Name = "Bar"&lt;br /&gt;Blah = True&lt;br /&gt;If Blah Then Foo Bar Else Bar Foo&lt;/p&gt;&lt;/font&gt;&lt;font color="#800080" size="2"&gt; &lt;p&gt;(d) is another mistake. The VB6 parser does not allow this, but VBScript does. As with #8, we couldn't fix it when we found it because it would have broken existing ASP page and web pages.&amp;nbsp; The&lt;/font&gt; &lt;font face="Lucida Console" color="#000080" size="2"&gt;End If&lt;/font&gt;&lt;font color="#800080" size="2"&gt; is ignored. &lt;/p&gt; &lt;p&gt;Funny story: I actually fixed this one for a beta release of the engines and a certain influential news site was broken by the fix. Bizarrely enough they had a web page with this syntax in it. They said they would give the new version of IE a bad review if upgrading broke even a single one of their hundreds of thousands of pages! Backwards compatibility is very, very important in the scripting world. Of course we rolled the change back, and there's a comment in the code now cautioning future maintenance programmers to never change it.&lt;/p&gt;&lt;/font&gt;&lt;/font&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=403799" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/ericlippert/archive/tags/VBScript/default.aspx">VBScript</category><category domain="http://blogs.msdn.com/ericlippert/archive/tags/Scripting/default.aspx">Scripting</category><category domain="http://blogs.msdn.com/ericlippert/archive/tags/Puzzles/default.aspx">Puzzles</category></item></channel></rss>