<?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 : Scripting</title><link>http://blogs.msdn.com/ericlippert/archive/tags/Scripting/default.aspx</link><description>Tags: Scripting</description><dc:language>en-US</dc:language><generator>CommunityServer 2.1 SP1 (Build: 61025.2)</generator><item><title>The void is invariant</title><link>http://blogs.msdn.com/ericlippert/archive/2009/06/29/the-void-is-invariant.aspx</link><pubDate>Mon, 29 Jun 2009 17:30:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9756024</guid><dc:creator>Eric Lippert</dc:creator><slash:comments>19</slash:comments><comments>http://blogs.msdn.com/ericlippert/comments/9756024.aspx</comments><wfw:commentRss>http://blogs.msdn.com/ericlippert/commentrss.aspx?PostID=9756024</wfw:commentRss><description>&lt;DIV class=mine&gt;
&lt;P&gt;[UPDATES below]&amp;nbsp;&lt;/P&gt;
&lt;P&gt;A while back I described &lt;A href="http://blogs.msdn.com/ericlippert/archive/2007/10/19/covariance-and-contravariance-in-c-part-three-member-group-conversion-variance.aspx" mce_href="http://blogs.msdn.com/ericlippert/archive/2007/10/19/covariance-and-contravariance-in-c-part-three-member-group-conversion-variance.aspx"&gt;a kind of variance that we’ve supported since C# 2.0.&lt;/A&gt; When assigning a method group to a delegate type, such that both the selected method and the delegate target agree that their return type is a reference type, then the conversion is allowed to be covariant. That is, you can say:&lt;/P&gt;&lt;SPAN class=code&gt;
&lt;P&gt;Giraffe GetGiraffe() { … }&lt;BR&gt;…&lt;BR&gt;Func&amp;lt;Animal&amp;gt; f = GetGiraffe;&lt;/P&gt;&lt;/SPAN&gt;
&lt;P&gt;This works logically because anyone who calls f must be able to handle any animal that comes back. The actual method claims to only return animals, and in fact, makes the stronger claim to only return giraffes. &lt;/P&gt;
&lt;P&gt;This works out in the CLR because the bits that make up a reference to an instance of Giraffe are exactly the same bits that make up a reference to that Giraffe interpreted as an instance of Animal. We can allow this magical conversion to happen because the CLR guarantees that it will all just work out without going in there and having to futz around with the bits.&lt;/P&gt;
&lt;P&gt;This is why this trick only works with reference types. A method that returns, say, a double cannot be converted via a covariant conversion to a delegate type that expects the method to return an object. Somewhere there would have to be code emitted that takes the returned double and boxes it to object; the bits of a double and the bits of a reference to an object boxing a double are completely different.&lt;/P&gt;
&lt;P&gt;But why doesn’t this trick work with void types? Here we have a method that returns some sort of success or failure code. Maybe we don’t care what it returns.&lt;/P&gt;&lt;SPAN class=code&gt;
&lt;P&gt;static bool DoSomething(bool b)&lt;BR&gt;{&lt;BR&gt;&amp;nbsp; if (b) return DoTheThing();&lt;BR&gt;&amp;nbsp; else return DoTheOtherThing();&lt;BR&gt;}&lt;/P&gt;
&lt;P&gt;Action&amp;lt;bool&amp;gt; action = DoSomething;&lt;/P&gt;&lt;/SPAN&gt;
&lt;P&gt;This doesn’t work. Why not? The caller of the action is not even going to &lt;EM&gt;use&lt;/EM&gt; the returned value, so it doesn’t matter one bit what it is! Shouldn’t “void” be considered &lt;EM&gt;a supertype of all possible types&lt;/EM&gt; for the purposes of covariant return type conversions from method groups to delegate types?&lt;/P&gt;
&lt;P&gt;No, and I’ll tell you why.&lt;/P&gt;
&lt;P&gt;Consider what happens when you do this:&lt;/P&gt;&lt;SPAN class=code&gt;
&lt;P&gt;bool x = DoSomething(true);&lt;/P&gt;&lt;/SPAN&gt;
&lt;P&gt;We spit out IL that does the following:&lt;/P&gt;
&lt;P&gt;(1) put true on the IL stack – the stack gets one deeper&lt;BR&gt;(2) call DoSomething – the argument is removed from the stack and the return value is placed on the stack.&amp;nbsp; Net, the stack stays the same size as before&lt;BR&gt;(3) stuff whatever on top of the stack into local variable x – the stack now returns to its original depth.&lt;/P&gt;
&lt;P&gt;Now consider what happens when you do this:&lt;/P&gt;&lt;SPAN class=code&gt;
&lt;P&gt;DoSomething(true);&lt;/P&gt;&lt;/SPAN&gt;
&lt;P&gt;We spit out IL that does the first two steps as before. But we cannot stop there! There is now a bool on the IL stack which needs to be removed. We generate a pop instruction to represent the fact that the returned bool has been discarded.&lt;/P&gt;
&lt;P&gt;Now consider what happens when you do this:&lt;/P&gt;&lt;SPAN class=code&gt;
&lt;P&gt;action(true);&lt;/P&gt;&lt;/SPAN&gt;
&lt;P&gt;The compiler believes that action is a void-returning method, so it does not generate a pop instruction. If we allowed you to stuff DoSomething into the action, then we would be allowing you to misalign the IL stack!&lt;/P&gt;
&lt;P&gt;But didn’t I say “&lt;A href="http://blogs.msdn.com/ericlippert/archive/2009/04/27/the-stack-is-an-implementation-detail.aspx" mce_href="http://blogs.msdn.com/ericlippert/archive/2009/04/27/the-stack-is-an-implementation-detail.aspx"&gt;the stack is an implementation detail?&lt;/A&gt;” Yes, but &lt;EM&gt;that’s a different stack&lt;/EM&gt;. The CLI specification describes a “virtual machine” which passes around arguments and returned values on a stack. An implementation of the CLI is required to make something that behaves like the specified machine, but it is not required to do so in any particular manner. It is not required to use the million-bytes-per-thread stack supplied to each thread by the operating system as its implementation of the IL stack; that’s a convenient structure to use, of course, but it’s an implementation detail that it does so.&lt;/P&gt;
&lt;P&gt;(As an aside: when we implemented the script engines, we also first specified our own private stack-based virtual machine. When we implemented it, we decided to put the information about “return addresses” – that is, “what code do I run next?” on the system stack, but we put arguments and return values of script functions in a stack-shaped block of memory that we allocated on our own. This made building the JScript garbage collector easier.)&lt;/P&gt;
&lt;P&gt;In practice, the jitter uses the system stack for some things and registers for other things. Return values are actually often sent back in a register, not on the stack. But that implementation detail doesn’t help us out when deciding what the conversion rules are; we have to assume that the implementation can do no more than what the CLI specification says. Had the CLI specification said “the returned value of any function is passed back in a ‘virtual register’” rather than having it pushed onto the stack, then we could have made void-returning delegates compatible with functions that returned anything. You can always just ignore the value in the register. But that’s not what the CLI specified, so that’s not what we can do. &lt;/P&gt;
&lt;P&gt;[UPDATE]&lt;/P&gt;
&lt;P&gt;A number of people have asked in the comments why we do not simply generate a helper method that does what you want. That is, when you say&lt;/P&gt;&lt;SPAN class=code&gt;
&lt;P&gt;Action&amp;lt;bool&amp;gt; action = DoSomething;&lt;/P&gt;&lt;/SPAN&gt;
&lt;P&gt;realize that as&lt;/P&gt;&lt;SPAN class=code&gt;
&lt;P&gt;static&amp;nbsp;void DoSomethingHelper(bool b)&lt;BR&gt;{&lt;BR&gt;&amp;nbsp;&amp;nbsp; bool result = DoSomething(b); // result is ignored&lt;BR&gt;}&lt;BR&gt;...&lt;BR&gt;Action&amp;lt;bool&amp;gt; action = DoSomethingHelper;&lt;/P&gt;&lt;/SPAN&gt;
&lt;P&gt;We could do that. But where would you like the line to be drawn? Should you be able to assign a&amp;nbsp;reference to a method that returns an int to a Func&amp;lt;Nullable&amp;lt;int&amp;gt;&amp;gt;? We could spit a helper method that converts the int to a nullable int.&amp;nbsp;What about Func&amp;lt;double&amp;gt;? We could spit a helper method that converts the int to a double. What about Func&amp;lt;object&amp;gt;? We could spit a helper method that boxes the int, unexpectedly allocating memory off the heap every time you call it. What about a Func&amp;lt;Foo&amp;gt; where there is a user-defined implicit conversion from int to Foo?&lt;/P&gt;
&lt;P&gt;We could be spitting arbitrarily complex fixer-upper methods that would seamlessly "do what you meant to say", and we have to stop somewhere.&amp;nbsp;The exact semantics of what we&amp;nbsp;do and do not&amp;nbsp;fix up would have to be designed, specified, implemented, tested, documented, shipped to customers and maintained forever. Those are costs. Plus, &lt;A class="" href="http://blogs.msdn.com/ericlippert/archive/2007/08/31/future-breaking-changes-part-two.aspx" mce_href="http://blogs.msdn.com/ericlippert/archive/2007/08/31/future-breaking-changes-part-two.aspx"&gt;every time we add a new conversion rule to the language we add breaking changes&lt;/A&gt;. The costs of those breaking changes to our customers have to be factored in.&lt;/P&gt;
&lt;P&gt;But more fundamentally, one of the design principles of C# is "if &lt;STRONG&gt;you say something wrong then &lt;EM&gt;we tell you&lt;/EM&gt; rather than trying &lt;EM&gt;to guess what you meant&lt;/EM&gt;&lt;/STRONG&gt;". JScript is deliberately a "muddle on through and do the best you can" language; C# is not. If what you want to do is make a delegate to a helper method then you express that intention by going right ahead and making that method.&lt;/P&gt;&lt;/DIV&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9756024" width="1" height="1"&gt;</description><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/Breaking+Changes/default.aspx">Breaking Changes</category><category domain="http://blogs.msdn.com/ericlippert/archive/tags/Code+Generation/default.aspx">Code Generation</category><category domain="http://blogs.msdn.com/ericlippert/archive/tags/Conversions/default.aspx">Conversions</category><category domain="http://blogs.msdn.com/ericlippert/archive/tags/Covariance+and+Contravariance/default.aspx">Covariance and Contravariance</category><category domain="http://blogs.msdn.com/ericlippert/archive/tags/Memory+Management/default.aspx">Memory Management</category></item><item><title>Iterators at the Summer Games</title><link>http://blogs.msdn.com/ericlippert/archive/2009/06/26/iterators-at-the-summer-games.aspx</link><pubDate>Fri, 26 Jun 2009 17:09:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9805525</guid><dc:creator>Eric Lippert</dc:creator><slash:comments>14</slash:comments><comments>http://blogs.msdn.com/ericlippert/comments/9805525.aspx</comments><wfw:commentRss>http://blogs.msdn.com/ericlippert/commentrss.aspx?PostID=9805525</wfw:commentRss><description>&lt;DIV class=mine&gt;
&lt;P&gt;&lt;A href="http://blogs.technet.com/heyscriptingguy/" mce_href="http://blogs.technet.com/heyscriptingguy/"&gt;Ed "Scripting Guy" Wilson&lt;/A&gt; was kind enough to ask me to be a &lt;A href="http://blogs.technet.com/heyscriptingguy/archive/2009/06/25/hey-scripting-guy-event-10-solutions-from-expert-commentators-beginner-and-advanced-the-1-500-meter-race.aspx" mce_href="http://blogs.technet.com/heyscriptingguy/archive/2009/06/25/hey-scripting-guy-event-10-solutions-from-expert-commentators-beginner-and-advanced-the-1-500-meter-race.aspx"&gt;guest commentator&lt;/A&gt; at this years &lt;A href="http://blogs.technet.com/heyscriptingguy/archive/tags/2009+Summer+Scripting+Games/default.aspx" mce_href="http://blogs.technet.com/heyscriptingguy/archive/tags/2009+Summer+Scripting+Games/default.aspx"&gt;Summer Scripting Games&lt;/A&gt;, which have just completed.&lt;/P&gt;
&lt;P&gt;I've been working on a series for this blog about some unusual cases in the design of the "iterator block" feature in C# 2.0; this bit from my commentary is going to be germane to that series. I thought I'd post it here as an appetizer before we get into&amp;nbsp;the main courses of the series. The series on iterators will probably run throughout July.&lt;/P&gt;
&lt;P&gt;The problem for event ten of the scripting games was to write a script which changes the priority of every new process that has a particular name.&lt;/P&gt;
&lt;P&gt;***********&lt;/P&gt;
&lt;P&gt;There’s an odd thing that you learn when working on developer tools: The people who &lt;I&gt;design&lt;/I&gt; and &lt;I&gt;build&lt;/I&gt; the tools are often not the experts on the actual real-world &lt;I&gt;use&lt;/I&gt; of those tools. I could tell you anything you want to know about the VBScript parser or the code generator or the runtime library, but I’m no expert on writing actual scripts that solve real problems. This is why I was both intrigued and a bit worried when the Scripting Guys approached me and asked if I’d like to be a guest commentator for the 2009 Summer Scripting Games.&lt;/P&gt;
&lt;P&gt;I wrote this script the same way most scripters approach a technical problem that they don’t immediately know how to solve; I searched the Internet for keywords from the problem domain to see what I could come up with. Of course, I already knew about our MSDN documentation, I had a (very) basic understanding of WMI, and I knew that the Scripting Guys had a massive repository of handy scripts. &lt;/P&gt;
&lt;P&gt;My initial naïve thought was that I would have to go with a polling solution; sit there in a loop, querying the process table every couple of seconds, waiting for new processes to pop up. Fortunately, my Internet searches quickly led me to discover that process startup &lt;I&gt;events&lt;/I&gt; can be treated as an endless &lt;I&gt;collection&lt;/I&gt; of objects returned by a WMI query. &lt;/P&gt;
&lt;P&gt;That got me thinking about &lt;STRONG&gt;the powerful isomorphism between &lt;I&gt;events&lt;/I&gt; and &lt;I&gt;collections&lt;/I&gt;.&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;A collection typically uses a “pull” model — the consumer asks for each item in the collection one at a time as needed, and the call returns when the item is available. Events typically work on a “push” model — the consumer registers a method that gets called every time the event fires. But not necessarily; the WMI provider implements events on a “pull” model. The event is realized as a collection of “event objects.” It can be queried like any other collection. Asking for the next event object that matches the query simply blocks until it is available. &lt;/P&gt;
&lt;P&gt;Similarly, &lt;STRONG&gt;collection iterators could be implemented on a “push” model&lt;/STRONG&gt;. They could call a method whenever the next item in the collection becomes available. The next version of the CLR framework is likely to have standard interfaces that represent “observable collections”, that is, collections that “push” data to you, like events do. The ability to treat events as collections and collections as events can lead to some interesting and powerful coding patterns.&lt;/P&gt;
&lt;P&gt;***********&lt;/P&gt;
&lt;P&gt;The rest of the solution and analysis is &lt;A href="http://blogs.technet.com/heyscriptingguy/archive/2009/06/25/hey-scripting-guy-event-10-solutions-from-expert-commentators-beginner-and-advanced-the-1-500-meter-race.aspx" mce_href="http://blogs.technet.com/heyscriptingguy/archive/2009/06/25/hey-scripting-guy-event-10-solutions-from-expert-commentators-beginner-and-advanced-the-1-500-meter-race.aspx"&gt;here&lt;/A&gt;.&lt;/P&gt;
&lt;P&gt;Have a good weekend!&lt;/P&gt;&lt;/DIV&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9805525" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/ericlippert/archive/tags/Scripting/default.aspx">Scripting</category><category domain="http://blogs.msdn.com/ericlippert/archive/tags/Iterators/default.aspx">Iterators</category></item><item><title>It Already Is A Scripting Language</title><link>http://blogs.msdn.com/ericlippert/archive/2009/06/24/it-already-is-a-scripting-language.aspx</link><pubDate>Wed, 24 Jun 2009 18:07:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9801664</guid><dc:creator>Eric Lippert</dc:creator><slash:comments>50</slash:comments><comments>http://blogs.msdn.com/ericlippert/comments/9801664.aspx</comments><wfw:commentRss>http://blogs.msdn.com/ericlippert/commentrss.aspx?PostID=9801664</wfw:commentRss><description>&lt;DIV class=mine&gt;
&lt;P&gt;My recent post about the &lt;EM&gt;possibility&lt;/EM&gt; of &lt;EM&gt;considering maybe someday perhaps&lt;/EM&gt; adding "top level" methods to C# in order to better enable "scripty" scenarios generated a surprising amount of immediate emphatic pushback. Check out the comments to see what I mean.&lt;/P&gt;
&lt;P&gt;Two things immediately come to mind.&lt;/P&gt;
&lt;P&gt;First off, the suggestion made by a significant number of the commenters is "instead of allowing top-level methods, strengthen the using directive." That is, if you said "using System.Math;" then all the static members of that class could be used without qualification.&lt;/P&gt;
&lt;P&gt;Though that is a perfectly reasonable idea that is requested frequently, it does not actually address the problem that top-level methods solve. A better "using" makes things easier for the developer writing the &lt;EM&gt;call&lt;/EM&gt;. The point of top-level methods for scripty scenarios is to make it easier on the developer writing the &lt;EM&gt;declaration&lt;/EM&gt;. The point is to eliminate the "ritual" of declaring an unnecessary class solely to act as a container for code.&lt;/P&gt;
&lt;P&gt;Second, and more generally, I am surprised by this pushback because of course &lt;STRONG&gt;C# already is a scripting language, and has had this feature for almost a decade.&lt;/STRONG&gt; Does this code fragment look familiar?&lt;/P&gt;&lt;SPAN class=code&gt;
&lt;P&gt;&amp;lt;%@ Page Language="C#" %&amp;gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;BR&gt;&amp;lt;script runat="server"&amp;gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;BR&gt;&amp;nbsp; void Page_Load(object sender, EventArgs e)&amp;nbsp;&lt;BR&gt;&amp;nbsp;&amp;nbsp;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// whatever&lt;BR&gt;&amp;nbsp;&amp;nbsp;}&lt;BR&gt;&amp;lt;/script&amp;gt;&lt;BR&gt;...&lt;BR&gt;&lt;/P&gt;&lt;/SPAN&gt;
&lt;P&gt;Where's the class? Where are the using directives that allow "EventArgs" to be used without qualification? Where's the code that adds this method group to the event's delegate? All the ritual seems to have been eliminated somehow. That sure looks like a "top-level method" to me. &lt;/P&gt;
&lt;P&gt;Of course we know that behind the scenes it isn't any such thing.&amp;nbsp;ASP.NET does textual transformations on the page to generate a class file. And of course, we recommend that you use the "code behind" technique to make a file that actually contains the methods in the context of an explicit&amp;nbsp;(partial) page class, to emphasize that yes, this is a class-based approach to server-side processing.&lt;/P&gt;
&lt;P&gt;But you certainly do not have to&amp;nbsp;use "code behind". If you're an ASP traditionalist (like me!)&amp;nbsp;and would&amp;nbsp;rather see C# as a "scripting language" that "scripts" the creation of content on a web server, you go right ahead. You can put your "top level" methods in "script" blocks and your "top level" statements in "&amp;lt;% %&amp;gt;" blocks and you'll thereby&amp;nbsp;avoid the ritual of having to be explicit about the containers for those code elements. The ASP.NET code automatically reorganizes your "script" code into something that the C# compiler can deal with, adding all the boring boilerplate code that has to be there to keep the compiler happy.&lt;/P&gt;
&lt;P&gt;But consider now&amp;nbsp;the burden placed upon the developers of ASP.NET by the language design. Those guys cannot simply parse out the C# text and hand it to the C# compiler. They've got to have a solid understanding of what the legal code container topologies are, and jump through hoops -- not particularly difficult hoops,&amp;nbsp;but hoops nevertheless -- to generate a class that can actually be compiled and executed.&lt;/P&gt;
&lt;P&gt;This same burden is placed upon &lt;EM&gt;every&lt;/EM&gt; developer who would like to expose the ability to add execution of end-user-supplied code to their application, whether that's in the form of adding extensibility via scripting, or by enabling evaluation of user-supplied expressions (such as queries). It's a burden placed on developers of productivity tools, like Jon Skeet's "snippet compiler", or LINQPad. It's a burden on developers who wish to experiment with REPL-like approaches to rapid development of prototypes, test cases, and so on.&lt;/P&gt;
&lt;P&gt;I am not particularly excited about&amp;nbsp;the convenience of the ability to save five characters by eliding the "Math." when trying to calculate a cosine. The&amp;nbsp;exciting value props&amp;nbsp;are that we might be able to&lt;STRONG&gt; lower the cost of building tools that extend the power of the C# language into third-party applications, &lt;/STRONG&gt;and at the same time&amp;nbsp;enable &lt;STRONG&gt;new ways to rapidly experiment and develop high-quality code.&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;Of course we do not want to wreck the existing value props of the language in doing so; as I said last time, we also believe that there is huge&amp;nbsp;value in the language design naturally leading professional, large-scale application developers towards&amp;nbsp;building well-factored component-based programs. &lt;/P&gt;
&lt;P&gt;Like all design decisions, when we're faced with a number of competing,&amp;nbsp;compelling, valuable and&amp;nbsp;noncompossible ideas, we've got to find a workable compromise. We don't do that except by &lt;STRONG&gt;considering all&amp;nbsp;the possibilites&lt;/STRONG&gt;, which is what we're doing in this case.&lt;/P&gt;&lt;/DIV&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9801664" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/ericlippert/archive/tags/Scripting/default.aspx">Scripting</category><category domain="http://blogs.msdn.com/ericlippert/archive/tags/ASP/default.aspx">ASP</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/Language+Design/default.aspx">Language Design</category></item><item><title>Why Doesn't C# Implement "Top Level" Methods?</title><link>http://blogs.msdn.com/ericlippert/archive/2009/06/22/why-doesn-t-c-implement-top-level-methods.aspx</link><pubDate>Mon, 22 Jun 2009 18:39:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9797817</guid><dc:creator>Eric Lippert</dc:creator><slash:comments>58</slash:comments><comments>http://blogs.msdn.com/ericlippert/comments/9797817.aspx</comments><wfw:commentRss>http://blogs.msdn.com/ericlippert/commentrss.aspx?PostID=9797817</wfw:commentRss><description>&lt;DIV class=mine&gt;
&lt;P&gt;C# requires that every method be in some class, even if it is a static method in a static class in the global namespace. Other languages allow "top level" functions. A&lt;A class="" href="http://stackoverflow.com/questions/1024171/why-c-is-not-allowing-non-member-functions-like-c/1027853#1027853" mce_href="http://stackoverflow.com/questions/1024171/why-c-is-not-allowing-non-member-functions-like-c/1027853#1027853"&gt; recent stackoverflow post asks why that is.&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;I am asked "why doesn't C# implement feature X?" all the time. The answer is always the same: because no one ever designed, specified, implemented, tested, documented and shipped that feature. All six of those things are necessary to make a feature happen. All of them cost huge amounts of time, effort and money. Features are not cheap, and we try very hard to make sure that we are only shipping those features which give the best possible benefits to our users given our constrained time, effort and money budgets.&lt;/P&gt;
&lt;P&gt;I understand that such a general answer probably does not address the specific question. &lt;/P&gt;
&lt;P&gt;In this particular case, the clear user benefit was in the past not large enough to justify the complications to the language which would ensue. By restricting how different language entities nest inside each other we (1) restrict legal programs to be in a common, easily understood style, and (2) make it possible to define "identifier lookup" rules which are comprehensible, specifiable, implementable, testable and documentable. &lt;/P&gt;
&lt;P&gt;By restricting method bodies to always be inside a struct or class, we make it easier to reason about the meaning of an unqualified identifier used in an invocation context; such a thing is always an invocable member of the current type (or a base type).&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Now, JScript.NET has this feature. (And in fact, JScript.NET goes even further; you can have program statements "at the top level" too.) A reasonable question is "why is this feature good for JScript but bad for C#?"&lt;/P&gt;
&lt;P&gt;First off, I reject the premise that the feature is "bad" for C#. The feature might well be good for C#, just not &lt;EM&gt;good enough&lt;/EM&gt; compared to its costs (and to the &lt;EM&gt;opportunity cost&lt;/EM&gt; of doing that feature &lt;EM&gt;instead of a more valuable feature&lt;/EM&gt;.) The feature might become good enough for C# if its costs are lowered, or if the compelling benefit to customers becomes higher.&lt;/P&gt;
&lt;P&gt;Second, the question assumes that the feature is good for JScript.NET. Why is it good for JScript.NET?&lt;/P&gt;
&lt;P&gt;It's good for JScript.NET because JScript.NET was designed to be a "scripty" language as well as a "large-scale development" language. "JScript classic"'s original design as a scripting language requires that "a one-line program actually be one line". If your intention is to make a language that allows for rapid development of short, simple scripts by novice developers then you want to minimize the amount of "ritual incantations" that must happen in every program. In JScript you do not want to have to start with a bunch of using clauses and define a class and then put stuff in the class and have a Main routine and blah blah blah, all this ritual just to get Hello World running.&lt;/P&gt;
&lt;P&gt;C# was designed to be a large-scale application development language geared towards pro devs from day one; it was never intended to be a scripting language. It's design therefore encourages enforcing the &lt;EM&gt;immediate&lt;/EM&gt; organization of even small chunks of code into &lt;EM&gt;components&lt;/EM&gt;. &lt;STRONG&gt;C# is a component-oriented language.&lt;/STRONG&gt; We therefore want to encourage programming in a component-based style and discourage features that work against that style.&lt;/P&gt;
&lt;P&gt;This is changing. "REPL" languages like F#, long popular in academia, are increasing in popularity in industry. There's a renewed interest in "scripty" application programmability via tools like Visual Studio Tools for Applications. These forces cause us to re-evaluate whether "a one line program is one line" is a sensible goal for hypothetical future versions of C#. Hitherto it has been an explicit non-goal of the language design.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;(As always, whenever I discuss the hypothetical "next version of C#", keep in mind that we have not announced any next version, that it might never happen, and that it is utterly premature to think about feature sets or schedules. All speculation about future versions of unannounced products should be taken as "for entertainment purposes only" musings, not as promises about future offerings.)&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;We are therefore &lt;EM&gt;considering&lt;/EM&gt; adding this feature to a hypothetical future version of C#, in order to better support "scripty" scenarios and REPL evaluation. When the existence of powerful new tools is predicated upon the existence of language features, that is points towards getting the language features done.&lt;/P&gt;
&lt;P&gt;UPDATE: &lt;A class="" href="http://blogs.msdn.com/ericlippert/archive/2009/06/24/it-already-is-a-scripting-language.aspx" mce_href="http://blogs.msdn.com/ericlippert/archive/2009/06/24/it-already-is-a-scripting-language.aspx"&gt;More thoughts on considerations motivating this potential change here&lt;/A&gt;.&lt;/P&gt;&lt;/DIV&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9797817" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/ericlippert/archive/tags/JScript+.NET/default.aspx">JScript .NET</category><category domain="http://blogs.msdn.com/ericlippert/archive/tags/JScript/default.aspx">JScript</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/Static+Methods/default.aspx">Static Methods</category><category domain="http://blogs.msdn.com/ericlippert/archive/tags/Language+Design/default.aspx">Language Design</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>A Book By Any Other Name Would Smell As Sweet</title><link>http://blogs.msdn.com/ericlippert/archive/2009/04/02/a-book-by-any-other-name-would-smell-as-sweet.aspx</link><pubDate>Thu, 02 Apr 2009 16:09:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9511286</guid><dc:creator>Eric Lippert</dc:creator><slash:comments>10</slash:comments><comments>http://blogs.msdn.com/ericlippert/comments/9511286.aspx</comments><wfw:commentRss>http://blogs.msdn.com/ericlippert/commentrss.aspx?PostID=9511286</wfw:commentRss><description>&lt;DIV class=mine&gt;
&lt;P&gt;As you might have gathered from my previous posts on the subject, I occasionally edit technical books as a hobby. It’s nice having a hobby that pays money instead of costing money. And I always learn something from every book.&lt;/P&gt;
&lt;P&gt;&lt;A href="http://www.apress.com/book/view/9781893115675" mce_href="http://www.apress.com/book/view/9781893115675"&gt;&lt;IMG title=MESWTWSH style="BORDER-RIGHT: 0px; BORDER-TOP: 0px; DISPLAY: inline; MARGIN: 0px 10px 0px 0px; BORDER-LEFT: 0px; BORDER-BOTTOM: 0px" height=244 alt=MESWTWSH src="http://blogs.msdn.com/blogfiles/ericlippert/WindowsLiveWriter/ABookByAnyOtherNameWouldSmellAsSweet_8AC3/MESWTWSH_5.jpg" width=194 align=left border=0 mce_src="http://blogs.msdn.com/blogfiles/ericlippert/WindowsLiveWriter/ABookByAnyOtherNameWouldSmellAsSweet_8AC3/MESWTWSH_5.jpg"&gt;&lt;/A&gt;Many years ago, on one of my first editing gigs, the editor asked me my opinion on what the book’s title should be. At the time I had no particularly coherent thoughts about how to title a book, but I’m almost always willing to offer an opinion on things I know little about. So I thought about it for a few minutes and responded that since the book was about &lt;EM&gt;how to manage enterprise IT systems by writing scripts that use the Windows Script Host&lt;/EM&gt;, that the title should be “&lt;U&gt;&lt;STRONG&gt;Managing Enterprise Systems With The Windows Script Host&lt;/STRONG&gt;&lt;/U&gt;”. After some back-and-forth discussion between me, the editor and the author, we actually settled on that title, amazingly enough.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;This is not a very good title for what is really a quite good book.&lt;/STRONG&gt; I realize this now, with the hindsight of a lot more experience in thinking about how to name things.&lt;/P&gt;
&lt;P&gt;Were I asked to criticize this title now, with that hindsight, I’d ask myself some pointed questions:&lt;/P&gt;
&lt;P&gt;Q: Is “&lt;STRONG&gt;managing&lt;/STRONG&gt;” what the target customer of the book describes themselves as doing? &lt;/P&gt;
&lt;P&gt;A: Maybe sometimes, but we can do better. The target audience typically describes themselves as “systems &lt;EM&gt;administrators&lt;/EM&gt;”, not “&lt;EM&gt;managers&lt;/EM&gt;”. Cut “managing” and replace it with “&lt;STRONG&gt;Administering&lt;/STRONG&gt;”.&lt;/P&gt;
&lt;P&gt;Q: What function does the word “&lt;STRONG&gt;Enterprise&lt;/STRONG&gt;” serve?&lt;/P&gt;
&lt;P&gt;A: It discourages home-computer users from buying the book. Which is good, because they are not our target audience. But “Managing” or “Administering” already does that. It also discourages small- or medium-business sys admins from buying the book and they &lt;EM&gt;are&lt;/EM&gt; in the target audience. Cut “Enterprise”.&lt;/P&gt;
&lt;P&gt;Q: Do we really need to call out that the things being administered/managed are “&lt;STRONG&gt;Systems&lt;/STRONG&gt;”?&lt;/P&gt;
&lt;P&gt;A: No, obviously that goes without saying. Cut “Systems”.&lt;/P&gt;
&lt;P&gt;Q: Then what noun is the object of the verb “Administering”?&lt;/P&gt;
&lt;P&gt;A: We need to tell the potential reader that this is a book about administering &lt;EM&gt;&lt;STRONG&gt;Windows&lt;/STRONG&gt;&lt;/EM&gt;. The noun “Windows” &lt;EM&gt;must&lt;/EM&gt; be in the title somewhere. Admins of other operating systems are explicitly not in our target audience and we must discourage them from buying this book. We look disingenuous if we don’t do that.&lt;/P&gt;
&lt;P&gt;Q: What does “&lt;STRONG&gt;With Windows Script Host&lt;/STRONG&gt;” communicate to the potential buyer?&lt;/P&gt;
&lt;P&gt;A: It logically ties the book to a &lt;EM&gt;particular tool&lt;/EM&gt; used to solve the customer’s problems. It puts the emphasis on the solution mechanism rather than on the customer’s problem.&lt;/P&gt;
&lt;P&gt;Q: If the customer needs a circular hole in a wall, do they care much about who manufactured the drill and the drill bit?&lt;/P&gt;
&lt;P&gt;A: No. Though there are better and worse drills, good enough is good enough. As long as the drill works reasonably well, they mostly care about the result. &lt;/P&gt;
&lt;P&gt;The implementation details of the solution are not particularly important to the customer, even if they’re the person doing the implementation. What’s important to the customer is the &lt;EM&gt;benefit&lt;/EM&gt; obtained by taking the advice in the book.&lt;/P&gt;
&lt;P&gt;Q: What is the compelling overall benefit to the customer of using the advice in the book?&lt;/P&gt;
&lt;P&gt;A: They can write scripts to &lt;EM&gt;automate tasks&lt;/EM&gt;, putting in some up-front time to write the script and accruing the benefit of having a previously time-consuming and irksome administration task performed &lt;EM&gt;quickly and automatically&lt;/EM&gt; by the script host.&lt;/P&gt;
&lt;P&gt;Whew. That was a lot of pointed questions.&lt;/P&gt;
&lt;P&gt;&lt;A href="http://www.apress.com/book/view/1590593979" mce_href="http://www.apress.com/book/view/1590593979"&gt;&lt;IMG title=AWA style="BORDER-RIGHT: 0px; BORDER-TOP: 0px; DISPLAY: inline; MARGIN: 0px 10px 0px 0px; BORDER-LEFT: 0px; BORDER-BOTTOM: 0px" height=244 alt=AWA src="http://blogs.msdn.com/blogfiles/ericlippert/WindowsLiveWriter/ABookByAnyOtherNameWouldSmellAsSweet_8AC3/AWA_3.jpg" width=195 align=left border=0 mce_src="http://blogs.msdn.com/blogfiles/ericlippert/WindowsLiveWriter/ABookByAnyOtherNameWouldSmellAsSweet_8AC3/AWA_3.jpg"&gt;&lt;/A&gt; I wasn’t there for this conversation, but I imagine that the editors and author went through a similar mental process when they prepared the second edition for publication. The second edition has a far better name: &lt;STRONG&gt;&lt;U&gt;Automating Windows Administration&lt;/U&gt;&lt;/STRONG&gt;. It contains keywords “Windows” and “Administration” which attract the target audience – professional administrators of Windows-based systems – and repels people not in the target audience. And it leads with the compelling benefit to the customer: automation. “Automation” makes work easier. Leading with “Managing” puts the emphasis on the hard part of the job, not on making it easier. And the new name&amp;nbsp;doesn’t tie the book or the reader to committing to a particular toolset.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Good naming is a hugely important aspect of design&lt;/STRONG&gt;; the name of a thing is almost always how the thing first enters the consciousness of a potential consumer. Next time, we’ll explore some more aspects of what makes a name “good” or “bad” for a particular purpose.&lt;/P&gt;&lt;/DIV&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9511286" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/ericlippert/archive/tags/Scripting/default.aspx">Scripting</category><category domain="http://blogs.msdn.com/ericlippert/archive/tags/Books/default.aspx">Books</category><category domain="http://blogs.msdn.com/ericlippert/archive/tags/Mistakes/default.aspx">Mistakes</category><category domain="http://blogs.msdn.com/ericlippert/archive/tags/Dialogue/default.aspx">Dialogue</category><category domain="http://blogs.msdn.com/ericlippert/archive/tags/naming/default.aspx">naming</category></item><item><title>Human sacrifice, dogs and cats living together, mass hysteria! and thread model errors!</title><link>http://blogs.msdn.com/ericlippert/archive/2007/05/07/human-sacrifice-dogs-and-cats-living-together-mass-hysteria-and-thread-model-errors.aspx</link><pubDate>Tue, 08 May 2007 02:22:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:2482620</guid><dc:creator>Eric Lippert</dc:creator><slash:comments>1</slash:comments><comments>http://blogs.msdn.com/ericlippert/comments/2482620.aspx</comments><wfw:commentRss>http://blogs.msdn.com/ericlippert/commentrss.aspx?PostID=2482620</wfw:commentRss><description>&lt;DIV class=mine&gt;
&lt;P&gt;Reader Shaka comments on &lt;A class="" href="http://blogs.msdn.com/ericlippert/archive/2006/07/07/659259.aspx" mce_href="http://blogs.msdn.com/ericlippert/archive/2006/07/07/659259.aspx"&gt;my post about error messages&lt;/A&gt; that "catastrophic failure" really does take the cake as being a terrible error message.&lt;/P&gt;
&lt;P&gt;I fondly remember the first time I saw "catastrophic failure" as an error message. I was an intern, running the build lab for Visual Basic for Applications, and I was trying to get the PowerPC cross-compiler working so that we could build PPC binaries on x86 hardware. (Note that this was in the early 1990's. The VS build lab is now an entire team of people who have dedicated circuits just for the cooling equipment for all their computers. We've come a long way from an intern, a closet, and six machines named after opponents of Godzilla (*).)&lt;/P&gt;
&lt;P&gt;Anyway, the compiler had a bug which caused it to run out of stack while compiling a particular module and the error was "catastrophic failure". This amused me to no end at the time. I laughed out loud, literally. I mean, &lt;EM&gt;fatal&lt;/EM&gt;, sure. That process is going &lt;EM&gt;down&lt;/EM&gt;. But "catastrophic"? I expect catastrophes to at least result in my hard disk becoming unreadable. I want bridges collapsing and floods and &lt;A href="http://frogstar.soylentgeek.com/wav/disaster.wav"&gt;mass hysteria&lt;/A&gt;!&lt;/P&gt;
&lt;P&gt;I have therefore always been rather embarrassed that the error message you get when you call the script engine on the &lt;A class="" href="http://blogs.msdn.com/ericlippert/archive/2003/09/18/53041.aspx" mce_href="http://blogs.msdn.com/ericlippert/archive/2003/09/18/53041.aspx"&gt;wrong thread&lt;/A&gt; is "catastrophic failure". That, unfortunately, is the somewhat breathless and overstated string associated with &lt;SPAN class=code&gt;E_UNEXPECTED&lt;/SPAN&gt;. Basically we want to say "you called us in a completely unexpected way which thoroughly violates the engine contract, please don't do that". But "catastrophic failure" is what you get. I wish now that we'd declared a new &lt;A href="http://blogs.msdn.com/ericlippert/archive/2003/10/22/53267.aspx"&gt;HRESULT&lt;/A&gt; just for "you've violated the engine contract". But it's far, far too late now.&lt;/P&gt;
&lt;P&gt;(*) In the interests of total accuracy: the OLE Automation build machines were named after Godzilla's opponents: Mothra, Monster Zero, etc. The VBA build machines were named after species of marine mammals: sei, humpback, etc.&lt;/P&gt;&lt;/DIV&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=2482620" width="1" height="1"&gt;</description><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><category domain="http://blogs.msdn.com/ericlippert/archive/tags/Threading/default.aspx">Threading</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>Local variables considered not very harmful</title><link>http://blogs.msdn.com/ericlippert/archive/2005/10/04/476938.aspx</link><pubDate>Tue, 04 Oct 2005 20:22:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:476938</guid><dc:creator>Eric Lippert</dc:creator><slash:comments>5</slash:comments><comments>http://blogs.msdn.com/ericlippert/comments/476938.aspx</comments><wfw:commentRss>http://blogs.msdn.com/ericlippert/commentrss.aspx?PostID=476938</wfw:commentRss><description>&lt;FONT face="lucida sans unicode"&gt;&lt;FONT color=#800080 size=2&gt;
&lt;P&gt;Like I said, that code from &lt;a href="http://blogs.msdn.com/ericlippert/archive/2005/09/30/475826.aspx"&gt;last time&lt;/A&gt;&amp;nbsp;was just test code, not real production code. Though clearly it works, I'd never write code like that in a million years. I'm not thrilled with the way it uses the &lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;answer&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt; variable of the outer scope as an accumulator, and it is profoundly weird that the "do this function n times" function is a member of the&amp;nbsp;&lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;Number&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt; prototype and not the&amp;nbsp;&lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;Function &lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt;prototype.&amp;nbsp; Worse still, we have a function that is essentially used as a composition operator that only makes sense to use on functions that have side effects and no arguments or returns.&amp;nbsp;That's a kind of&amp;nbsp;crazy way to do composition operations.&lt;/P&gt;
&lt;P&gt;I'd probably do something more like this:&lt;/P&gt;
&lt;P&gt;First, define a self-composition &lt;I&gt;factory&lt;/I&gt; on the &lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;Function&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt; prototype, so that it is of general use on all functions of one argument, not just functions of no arguments and no returns&amp;nbsp;that have side effects. What we'll do is make a new member function for every function object that returns a new function which is equivalent to calling the input function n times:&lt;/P&gt;&lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;
&lt;P&gt;Function.prototype.times = function(n) {&lt;BR&gt;&amp;nbsp; var f = this;&lt;BR&gt;&amp;nbsp; return function (x) {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;while (n &amp;gt; 0)&amp;nbsp;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;x = f(x);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; --n;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return x;&lt;BR&gt;&amp;nbsp; };&lt;BR&gt;}&lt;/P&gt;&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt;
&lt;P&gt;Obviously we don't need to compose functions of more than one argument because we want to feed the &lt;I&gt;single&lt;/I&gt; output back into the input.&amp;nbsp;&amp;nbsp;Now we compose the function "multiply something by x" with itself&amp;nbsp;n times. That gives us the function "multiply something by x, n times".&amp;nbsp; Pass 1 to that function and we have a handy &lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;raiseTo&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt; function:&lt;/P&gt;
&lt;P&gt;&lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;Number.prototype.raiseTo = function(power) { &lt;BR&gt;&amp;nbsp; var x = this;&lt;BR&gt;&amp;nbsp; return function(y) {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;return x * y&lt;BR&gt;&amp;nbsp; }.times(power)(1);&lt;BR&gt;}&lt;/P&gt;&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt;
&lt;P&gt;No fuss, no muss, no accumulators, no side effects, no non-number-related functions on the number prototype.&amp;nbsp;I like it!&lt;/P&gt;
&lt;P&gt;Heck, if we wanted to get &lt;I&gt;really&lt;/I&gt; crazy then&amp;nbsp;we could eliminate the local variables entirely by introducing another function constructor in-line:&lt;/P&gt;&lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;
&lt;P&gt;Function.prototype.times = function(n) {&lt;BR&gt;&amp;nbsp; return function(f) {&amp;nbsp;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return function (x) {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;while (n &amp;gt; 0) {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; x = f(x);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; --n;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return x;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;BR&gt;&amp;nbsp; }(this);&lt;BR&gt;} &lt;/P&gt;
&lt;P&gt;Number.prototype.raiseTo = function(power) { &lt;BR&gt;&amp;nbsp; return function(x) {&lt;BR&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;return function(y) {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return x * y&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;&amp;nbsp; }(this).times(power)(1);&lt;BR&gt;}&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt;&lt;/P&gt;
&lt;P&gt;Local variables are actually an unnecessary syntactic sugar in Jscript.&amp;nbsp; We can do everything that local variables do by cleverly nesting function scopes.&amp;nbsp;However, it becomes &lt;I&gt;somewhat&lt;/I&gt; less easy to read, so I would stick to using local variables if I were you!&lt;/P&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=476938" 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/Scripting/default.aspx">Scripting</category></item><item><title>Guru meditations on scope chains of closures</title><link>http://blogs.msdn.com/ericlippert/archive/2005/09/30/475826.aspx</link><pubDate>Fri, 30 Sep 2005 22:41:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:475826</guid><dc:creator>Eric Lippert</dc:creator><slash:comments>11</slash:comments><comments>http://blogs.msdn.com/ericlippert/comments/475826.aspx</comments><wfw:commentRss>http://blogs.msdn.com/ericlippert/commentrss.aspx?PostID=475826</wfw:commentRss><description>&lt;FONT face="lucida sans unicode"&gt;&lt;FONT color=#800080 size=2&gt;
&lt;P&gt;I just had a really interesting meeting with some of the scripting community MVPs.&amp;nbsp; I may write up some notes on that meeting here next week, so watch this space.&lt;/P&gt;
&lt;P&gt;In other news, someone asked me&amp;nbsp;last night&amp;nbsp;(and I quote)&lt;/P&gt;
&lt;BLOCKQUOTE dir=ltr style="MARGIN-RIGHT: 0px"&gt;
&lt;P&gt;&lt;/FONT&gt;&lt;EM&gt;&lt;FONT size=2&gt;Oh ECMA guru, can you provide a succinct explanation of why the following code works, but if I replace &lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;x&lt;/FONT&gt;&lt;FONT size=2&gt; with &lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;this&lt;/FONT&gt;&lt;FONT size=2&gt; it fails?&lt;/P&gt;&lt;/BLOCKQUOTE&gt;&lt;/FONT&gt;&lt;/EM&gt;&lt;FONT color=#800080 size=2&gt;&lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;
&lt;P&gt;Number.prototype.times = function(f) {&lt;BR&gt;&amp;nbsp; for(var i = 0; i &amp;lt; this; i++)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; f(); &lt;BR&gt;} &lt;BR&gt;Number.prototype.raiseTo = function(n) { &lt;BR&gt;&amp;nbsp; var answer = 1; &lt;BR&gt;&amp;nbsp; var x = this; &lt;BR&gt;&amp;nbsp; n.times(function(){ answer = &lt;B&gt;x &lt;/B&gt;* answer;}); // succeeds&lt;BR&gt;//n.times(function(){ answer = &lt;B&gt;this &lt;/B&gt;* answer;}); // fails!&lt;BR&gt;&amp;nbsp; return answer; &lt;BR&gt;} &lt;BR&gt;(3).raiseTo(2).raiseTo(5); &lt;/P&gt;&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt;
&lt;P&gt;Well I'd hardly describe myself as a guru, but I take the questioner's point -- surely if you set &lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;x&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt; to &lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;this&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt; then &lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;x&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt; and &lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;this&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt; should be aliases for each other, right?&lt;/P&gt;
&lt;P&gt;Often. But not in this case. &lt;/P&gt;
&lt;P&gt;The inner function's execution context contains a scope chain that includes the variable object of the outer function, so the inner function can see &lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;x&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt; by looking up the scope chain. &lt;STRONG&gt;But &lt;/STRONG&gt;&lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;&lt;STRONG&gt;this &lt;/STRONG&gt;&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt;&lt;STRONG&gt;is not a variable&lt;/STRONG&gt;, so it is not member of the outer function's variable object. Rather, it is a member of the outer function's execution context.&lt;/P&gt;
&lt;P&gt;Therefore the inner function's execution context gets the &lt;I&gt;global&lt;/I&gt; &lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;this&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt;, in accordance with the ECMAScript specification, revision 3, section 10.2.3:&lt;/P&gt;
&lt;BLOCKQUOTE dir=ltr style="MARGIN-RIGHT: 0px"&gt;
&lt;P&gt;&lt;EM&gt;The caller provides the &lt;/EM&gt;&lt;/FONT&gt;&lt;EM&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;this&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt; value. If the &lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;this&lt;/FONT&gt;&lt;FONT color=#800080 size=2&gt; value provided by the caller is not an object (including the case where it is &lt;/FONT&gt;&lt;FONT face="Lucida Console" color=#333399 size=2&gt;null&lt;/FONT&gt;&lt;/EM&gt;&lt;FONT color=#800080 size=2&gt;&lt;EM&gt;), then the this value is the global object.&lt;/EM&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;The global object is not something that can be multiplied, so the alternate version of the program fails.&lt;/P&gt;
&lt;P&gt;The code above was of course not real production code, it was just code that came up while testing an engine implementation. Obviously JScript already has a built-in power function that works much better than this crazy thing. But I'm in an expansive mood, so next time I'll talk a bit about some of the shortcomings of this programming style, and some ideas for improving it.&lt;/P&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=475826" 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/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>Implementing Event Handling, Part One</title><link>http://blogs.msdn.com/ericlippert/archive/2005/09/09/463215.aspx</link><pubDate>Sat, 10 Sep 2005 01:35:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:463215</guid><dc:creator>Eric Lippert</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/ericlippert/comments/463215.aspx</comments><wfw:commentRss>http://blogs.msdn.com/ericlippert/commentrss.aspx?PostID=463215</wfw:commentRss><description>&lt;FONT face="lucida sans Unicode" color=purple size=2&gt;
&lt;P&gt;Back in February I posted a bit about &lt;a href="http://blogs.msdn.com/ericlippert/archive/2005/02/15/373330.aspx"&gt;how script hosts such as Windows Script Host dynamically hook up event sources (objects) to event sinks (chunks of script that run when the event fires.)&lt;/A&gt; It has become apparent from some questions I've received recently that it would be helpful to have a more detailed explanation of how event handling works in COM, and how that applies to late-bound scripting languages. &lt;/P&gt;
&lt;P&gt;We'll start in the early-bound world and then move into the scripting world&amp;nbsp;next week.&lt;/P&gt;
&lt;P&gt;Suppose you've got an object &lt;FONT color=#000080&gt;Timer&lt;/FONT&gt; that has methods &lt;FONT color=#000080&gt;Start&lt;/FONT&gt; and &lt;FONT color=#000080&gt;Stop&lt;/FONT&gt;, and event &lt;FONT color=#000080&gt;Tick&lt;/FONT&gt;. The methods are straightforward. We define an interface that has these methods on it:&lt;/P&gt;
&lt;P&gt;&lt;FONT face="lucida console" color=#000080&gt;interface ITimer : public IUnknown&lt;BR&gt;{&lt;BR&gt;public:&lt;BR&gt;&amp;nbsp; virtual void Start(int interval) = NULL;&lt;BR&gt;&amp;nbsp; virtual void Stop() = NULL;&lt;BR&gt;}&lt;BR&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;When users want to call those methods, they just get a pointer to the &lt;FONT color=#000080&gt;IUnknown&lt;/FONT&gt; of the object, &lt;FONT color=#000080&gt;QueryInterface&lt;/FONT&gt; it for &lt;FONT color=#000080&gt;ITimer&lt;/FONT&gt;, and then call the appropriate method on the virtual function table. &lt;/P&gt;
&lt;P&gt;But the user doesn't just want to call the timer. Not much point in that! They want the timer to inform some &lt;EM&gt;other&lt;/EM&gt; piece of code whenever a tick event occurs. Somehow the sink - the listener function&amp;nbsp;- is going to have to be called. This means that the timer code has to be &lt;EM&gt;running&lt;/EM&gt; and it has to &lt;EM&gt;call some arbitrary code&lt;/EM&gt; that it knows nothing about.&lt;/P&gt;
&lt;P&gt;How the timer code manages to run itself is a topic for another day; today we'll just worry about getting the call from the source to the sink. The sink is going to have to somehow register itself with the source, and they'll negotiate what interface the source will call on the sink when the event occurs. In this case the sink wants to know when a tick happens, so the sink should implement something like&lt;/P&gt;
&lt;P&gt;&lt;FONT face="lucida console" color=#000080&gt;interface ITick : public IUnknown&lt;BR&gt;{&lt;BR&gt;public:&lt;BR&gt;&amp;nbsp; virtual void Tick(ITimer * pSource) = NULL;&lt;BR&gt;}&lt;BR&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;OK, so suppose we have a source that implements &lt;FONT color=#000080&gt;ITimer&lt;/FONT&gt; and a sink that implements &lt;FONT color=#000080&gt;ITick&lt;/FONT&gt;. Somehow they have to get hooked up.&amp;nbsp; (Error checking removed.) &lt;/P&gt;
&lt;P&gt;
&lt;P&gt;&lt;FONT face="lucida console" color=#000080&gt;pSource-&amp;gt;QueryInterface(IID_IConnectionPointContainer, &amp;amp;pContainer);&lt;BR&gt;pContainer-&amp;gt;FindConnectionPoint(IID_ITick, &amp;amp;pConnection);&lt;BR&gt;pConnection-&amp;gt;Advise(pSink, &amp;amp;cookie);&lt;BR&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;The sink says to the source "&lt;EM&gt;do you contain connection points that can call me back on &lt;FONT color=#000080&gt;ITick&lt;/FONT&gt;?"&lt;/EM&gt; The source says "&lt;EM&gt;sure, here's an object that you can register yourself with that will call you back&lt;/EM&gt;". The sink then says "&lt;EM&gt;Super, here's a pointer back to me, and please give me a 'cookie' number that I can use to uniquely identify this relationship so that I can shut it down later&lt;/EM&gt;."&lt;/P&gt;
&lt;P&gt;The source now has a pointer to the sink, so when a tick event occurs, the source can call the sink.&lt;/P&gt;
&lt;P&gt;Next time we'll explore what happens in the scripting world where the sink only speaks &lt;FONT color=#000080&gt;IDispatch&lt;/FONT&gt;. &lt;/P&gt;&lt;/FONT&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=463215" width="1" height="1"&gt;</description><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></channel></rss>