Fabulous Adventures In Coding

Eric Lippert's Blog

Some Quick Notes On Variable Scoping

Here's a question I got a while back:

In a VBS or ASP file, the following code doesn't work, which I understand:

Option Explicit
s = "hello"

However, the following code works fine:

Option Explicit
s = "hello"
Dim s

Why can we use a variable before declaring it in VBScript?

A similar situation exists in JScript. This is illegal:

print(s);

But this is legal:

print(s);
var s;

What's up with that? Well, let me ask you this -- if you think that looks weird, why do you think this looks normal?

Dim s
s = Foo(123)
Function Foo(x)
  Foo = x + 345
End Function

There the function is being used before it is declared, but that doesn't bug you, right?

Similarly, variables can be used before they are declared. The behaviour is by design. Variable declarations and functions are logically "hoisted" to the top of their scope in both VBScript and JScript.

In JScript, both functions and variables may be redeclared at any time. In VBScript, declaring a variable twice in the same script block is illegal, but redefinition in another block is legal. Procedures may be redeclared at will except if the procedure is in a class, in which case redeclaration is illegal.

OK, that stuff is reasonably common knowledge, but it gets weirder. Did you know that this is legal in VBScript?

s = Foo(123)
If Blah Then
  Function Foo(x)
    Foo = x + 345
  End Function
End If

Not recommended, but legal.  There's a sad story about why that's legal which I might tell at another time.  Suffice to say that it involves ASP pages, a bug, and a rather recalcitrant online news service.  (This behaves as though the function were declared outside the conditional -- you can't do conditional function definition in VBScript, sorry.)

There was a long internal debate over these variable declaration issues back in 1996. There was an even longer debate in the ECMA committee over exactly what the hoisting algorithm should be in ECMAScript. I once knew every such argument about program language syntax in all the scripting languages of men, elves and dwarves -- even now, a score of them come to mind! But it has been eight long years since 1996. I have seen many battles and many fruitless victories. In short, recalling the details to mind is difficult; it's all pretty much a blur now.  I'm going to have to rely on the spec.

In JScript, the hoisting spec is as follows (Section 12.2 of ECMA specification 262, Revision 3)

If the variable statement occurs inside a FunctionDeclaration, the variables are defined with function-local scope in that function […] Otherwise, they are defined with global scope […] Variables are created when the execution scope is entered. A Block does not define a new execution scope. Only Program and FunctionDeclaration produce a new scope. Variables are initialised to undefined when created. A variable with an Initialiser is assigned the value of its AssignmentExpression when the VariableStatement is executed, not when the variable is created.

Note that this implies that this silly program

print(v);
{
  var v = 123;
}
print(v);

is semantically exactly the same as

var v;
print(v);
v = 123;
print(v);

Waldemar Horwat's proposal for ECMAScript 4 further complicates the hoisting algorithm. In E3 there are only global and function scopes, and declarations are hoisted to the top of the “nearest“ scope. In the proposed E4 spect there are global, package, class, function, block, for-statement and catch-clause scopes. In general, declarations are hoisted to the top of their scope, but for backwards compatibility, sometimes variable declarations have to be hoisted to the nearest global, package, class or function scope.

I want to talk some more about the lack of C++-style block scopes in JScript, but that will have to wait for another day.

 

Published Friday, June 18, 2004 9:44 AM by Eric Lippert
Filed under: , ,

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS

Comments

 

grey said:

vb, javascript, etc. are not lexically scoped.

at one point in time, i remember the following bombing out on me:

Recurse(1, 10)
Function Recurse(current, stop)
Dim interval
interval = 1
If current <= stop Then
Recurse(current + interval, stop)
End If
End Function

The second time the function was called, it puked that the variable "interval" was already declared.

This leads to showing that vb is not lexically scoped, and as such, I believe all Dims, etc. are pulled in first during runtime. Hence why you have to do a ReDim at times. It's a one-time declaration for a variable name for the entire life of the execution.
June 18, 2004 10:19 AM
 

Eric Lippert said:

No, VBScript and JScript are lexically scoped. (The "with' block in JScript leads to some dynamism in scope resolution, but lets ignore that for now.)

Your program -- once I removed the four syntax errors -- compiles and runs just fine on my box.

(For those following along at home: in a "lexically scoped" language, the binding between a variable name and the scope containing the variable can be determined from the compile-time text of the program. In a "dynamically scoped" language, a given name can be bound to a different scope depending on runtime conditions. Lisp is dynamically scoped.)

>Hence why you have to do a ReDim at times

No, redim resizes an array. It doesn't redeclare a variable.

I think you may be misremembering something, or have misinterpreted an error message somewhere along the way. Can you give me an example of a VBScript program that shows the bad behaviour that you describe?

June 18, 2004 10:26 AM
 

Ricky Dhatt said:

Your link to ECMAScript 4 is mangled. Maybe you meant:
http://www.mozilla.org/js/language/es4/core/definitions.html#hoist ?

Since all I have been doing recently is application scripting with JScript, this is *great* stuff. Keep it up!
June 18, 2004 3:10 PM
 

Eric Lippert said:

Fixed. Thanks.
June 18, 2004 3:13 PM
 

Peter Torr said:

Oh boy, you don't want to know how many hours we spent talking about hoisting in ECMA meetings.
June 29, 2004 8:43 PM
 

Bob Riemersma said:

I sure wish that "hoisting" had not been done in VBScript. Not to be insensitive about it, but I could (almost) hardly care less what was done in JScript. I'll save time by keeping my rant about "take a stab at what the coder meant" languages and language processors to myself. The semicolon thing has been beat to death.

My pain comes from all of the VBScript written by others that I've had to compile as VB6 over the years. If only I'd taken the time to write something to automate the hoisting. I already had a "grabber/packager" for the embedded literal HTML and the wrapping of "outer scope" code as Sub Page or whatever anyway. So much for thinking (every time) that "this is the last time."

Oh well, such code invariably needs a lot of hand-tweaking anyway to get rid of bugs, dead code, and other absurdities.

Still, how the heck did that philosophy ever get incorporated into VBScript?


BTW: ReDim was always an odd creature. Most bizarre to me was that it could be used in place of Dim, where I think it had a special significance in regard to storage allocation in the QB/PDS/VBDOS context. Firing up VBDOS just now I see it's there all right. Remember all that DGROUP vs. "far memory" stuff? Thanks for nothing Intel.

Then there's the seldom used (today) Erase statement... but I digress.
July 3, 2004 7:27 AM
 

Eric Lippert said:

> Still, how the heck did that philosophy ever get incorporated into VBScript?

The decision was before my time, and somewhat controversial at the time. I have always been opposed to it -- however, we're stuck with it now.

And yeah, Redim and Erase are both a little weird.
July 12, 2004 11:34 AM
 

conditional connection string | keyongtech said:

January 18, 2009 11:29 AM
 

ASP variable declaration bug or feature?! | keyongtech said:

January 21, 2009 11:34 PM

Leave a Comment

(required) 
(optional)
(required) 
Submit

About Eric Lippert

Eric Lippert is a senior developer on the Microsoft C# compiler team. Before that he worked on the framework of Visual Studio Tools For Office. Before that, he worked on the compilers, runtimes and tools for VBScript, JScript, Windows Script Host and other Microsoft Scripting technologies. He lives in Seattle and spends his free time editing books about programming languages, playing the piano, and trying to keep his tiny sailboat upright in Puget Sound.

This Blog

Syndication


© 2009 Microsoft Corporation. All rights reserved. Terms of Use  |  Trademarks  |  Privacy Statement
Microsoft
Page view tracker