Fabulous Adventures In Coding
Eric Lippert is a principal developer on the C# compiler team. Learn more about Eric.
A few short takes today:
I wrote the name table logic over the weekend but it is not ready to post yet. For those of you following the conversation in yesterday's comments about whether I should use standard templates or roll my own, I ended up rolling my own non-template hash table. I'll discuss that design decision in more detail when I actually post the code.
Those of you who read the Joel On Software forum are undoubtedly familiar with the witty and urbane postings of Philo. You might not know that in his day job, he's an evangelist for, among other things, VSTO. I'm looking forward to seeing what he has to say about the Office dev community on his blog.
Runtime Typing in VBScript
Joel and I got into a discussion recently about VBScript's ambiguous use of parens. Joel asked:
In the VBScript parser, if you have a = b(3) you don't know if b() is a function call or an array lookup until you run the code because b is a variant… how do you compile such a thing?
Indeed, this situation is ambiguous and we do no type inference at compile time. We can tell declared names from undeclared names and optimize accordingly, but we don't tell whether something is an array, a procedure or a method call on an object. (Remember, if b is a collection, this might be sugar for b.item(3) )
VBScript compiles to a simple proprietary bytecode format which is then run through an interpreter. Consider this program:
Dim Aaa(10)Dim BbbBbb = Array(123)Function Ddd(z)End Functionx = Aaa(0)x = Bbb(0)x = Ccc(0)x = Ddd(0)
The first two assignments to x get compiled into something like this bytecode:
BOS Beginning of statementIntConst 0 Push argument on stackCallLocal 1 1 Call local variable #1 (Aaa), with one argument -- pops arguments, pushes result.StoreNamed 'x' Pop the top of stack into variable 'x'
Since we cannot find a dimensioned variable corresponding to the last two, both generate something like this instead of the local call:
CallNamed 'Ccc' 1
Which is slightly slower but logically the same. Figuring out what to do happens entirely at runtime. First, we resolve the local variable reference or name into some kind of variant. We then check to see which of these situations we're in:
We could, I suppose, deduce that a declared variable is typed as an array, but we don't. Doing so would save hardly any time, as the check to see if a given variant is an object or an array is extremely simple, and it would complicate the code generator.
And I know what you're going to ask -- no, there is no publically available utility program that dumps the bytecode, sorry!