Projects » Rants » The Flangy Guide to Hating VBScript

The Flangy Guide to Hating VBScript

By Adam Vandenberg

I wrote a new introduction for this article, 14 Apr 2005.

www: As seen on the WWW.  Steal this logo.

VBScript is, to put it mildy, not my favorite language. Python currently holds that distinction. Unforutnately, VBScript under ASP has been what I've spent most of the last two years working in.

Basically, this can be summed up as "VBS isn't Python". If you want the details, read on. Note that this is directed at VBScript running via ASP.

The Big One

No concept of modules
One namespace to rule them all, and in the darkness bind them.

VBScript does not let you define modules. This is enough for me to declare the whole language an AmorphousBlobOfHumanInsensitivity.

Modules let you group a bunch of functions or classes together and organize their names in such a way that they won't conflict with other parts of your system.

The closest you can get, which is very far from ideal, is to use SSI style includes. But this just takes the target file and dump it into your ASP page before compiling the script.

You can't include the same chunk of code twice without causing Name Redefined errors. This becomes a problem if two different includes are each including the same file.

If you try to include to chunks of code that each define their own "const DEFAULT_VALUE", you're screwed. Since there is only one namespace you are forced to use naming tricks to keep it uncluttered, such as prefixing all the functions in an include with a name and an underscore.

If VBS had modules, and specifically the ability to import them dynamically, I'd be able to forgive pretty much anything else wrong with it.

The Medium Ones

No lists

VBScript at least comes with a Dictionary object. But it doesn't support lists. It has fixed-length arrays, but you have to resize them manually via Redim, which has poor performance.

Any so-called scripting language, even any so-called real language really ought to have a list type. Even C++ gives you this as the STL Vector.

Annoying object assignment semantics

Let's say you have a COM object. This COM object has a method that returns an array of stuff, which you want to iterate over:

stuff = MyObj.getSomething
for each thing in stuff
 .. do something with thing ..
next

All is good with the universe. But wait! It turns out that we want to return some extra bits of information with this array. What to do? Ah, we'll just change the method to return a COM object that implements the collection iterface. Then for each will still work, and we can call methods on it.

And now, the problem: Arrays aren't objects and objects are. In order to set a variable to an object you must use the "set" keyword:

set stuff = MyObj.getSomething

This means that you have to go through all of your code and add set. This is a bletcherous bit of implemntation exposure.

It turns out that the "set" keyword is needed so that VBS knows you mean to assign the object to the variable, and not assign the default property to the variable. It makes me wonder if default properties are worth it, but I haven't used Visual Basic proper enough to know what it gets you.

Annoying function / sub distinction

Aside:
If you are more of a purist, subs are called for their side-effects (they do work and change state), while functions should just return a value and not change state.

Anyhoo, subs and functions in VBScript.

You can define subs and functions that don't take parameters with or without parenthesis. You can then call these with or without parenthesis:

sub s_noparam1
	WScript.Echo "sub noparam1"
end sub

sub s_noparam2() WScript.Echo "sub noparam2" end sub

function f_noparam1 WScript.Echo "function noparam1" end function

function f_noparam2() WScript.Echo "funciton noparam2" end function

s_noparam1 s_noparam1()

s_noparam2 s_noparam2()

f_noparam1 f_noparam2

Ok, so this isn't all that annoying in the grand scheme of things. But it get worse.

As you can see above, none of those subs or functions return values. Subs can't, of course, but functions can. Suprisingly the following code is all legal:

function f_noparam3
	WScript.Echo "f3"
	
	f_noparam3 = "a"
end function

a = f_noparam3 a = f_noparam3() f_noparam3 f_noparam3()

Ugh! If you came from some other language you might think that a = f_noparam3 would let you set a to be a reference to the function. Nope, VBScript doesn't have first-class functions (but see GetRefByName in VBScript 5.5).

Ignoring the return value of a function has a long and noble tradition (did you know that printf returns a value?), but people who abide by the aside at the top of this topic are cringing.

So far this has mostly be syntactic sand, I haven't gotten the real issue.

sub s_param1 (a)
	WScript.Echo a
end sub

sub s_param2 (a, b) WScript.Echo a end sub

s_param1 "x1" s_param1("x2")

s_param2 "x3", "y3" s_param2("x4", "y4")

Here are two subs, one that takes one parameter and one that takes two parameters. All of this code is valid except the last line!

A sub of one parameter can be called with or without parenthesis, but a sub of more than one parameter cannot be called with parenthesis or it is an error.

And how about this:

function f_param1(b)
	WScript.Echo b
	f_param = b
end function

f_param1 "y1" f_param1("y2")

a = f_param1("y3") a = f_param1 "y4"

All of this code is legal except for the last line again. You can omit the parenthesis if you are not using the return value, but use the value and you must include parenthesis.

function f_param2 (a, b)
	WScript.Echo a
	f_param2 = a
end function

f_param2 "z1", "a" f_param2("z2", "a")

a = f_param2 "z3", "a" a = f_param2("z4", "a")

In the code above, the z2 and z3 lines are both illegal. And the error on the z2 line? "Cannot use parenthesis when calling a Sub". Argh! I'm calling a function, but I'm not using it's value.

It seems to me that always requiring parenthesis would be easier. If I decide to change a sub to a function or a function to a sub, then I have to comb through code and toggle parens in or out.

No doubt the aside people would say that this sort of change points to a bad design, and if I'd followed the aside in the first place I wouldn't need to that make sort of change.

Well yes, I agree, but I also have inherited code to deal with and code being done by people who aren't as into applying theory as we are.

Awful error handling

VBScript doesn't have try/catch exception handling. By defaut any error stops processing. You can put an on error resume next statement in your code to prevent errors from ending execution. This sets properties on the built-in Err object, which you can then check. But you have to remember to check it on anything that could cause an error, or you'll miss the error!

I'd much rather have proper try/catch/final/whatever blocks.

Also, consider the following code:

option explicit
on error resume next

while i < 10 WScript.Echo "loop" i = i + 1 wend

option explicit tells VBScript that all varibles must be declared before use. But on error resume next tells it to go to the next line if an error occurs.

The code above goes into an infinite loop. i is not defined, but each reference just causes an error and moves to the next line.

No native functions

You can't write some C / C++ functions and make them available to your scripts. Well, you can, but you have to wrap them into a COM object. So if you want to expose a bunch of utility functions you have to go through the rigamarole of making it a COM object and registering it on the server.

Minor Lameness

No dictionary syntax

VBScript provides a Dictionary object (or Map or Hashtable, depending on what you call it). But you need to call methods on the object to access the Dictionary. Since a scripting langauge is supposed to make the easy things easy, and since Dictionaries are such a useful datatype to have, I'm all for having syntax to access them.

Type conversion lameness

If you have a COM object that returns DWORD values they cannot be directly compared to numbers. You either need to use clng() or change your COM object to return longs instead. Even though DWORDs and longs are the same thing.

CONSTs are really const

You can't define a constant out of other constants. This is illegal:

const SERVER = "http://myserver.com"
const MEDIAPATH = SERVER & "/media/"

It would be nice if that worked, since it does in various other flavors of Visual Basic.

Line continuation characters

If you code spans multiple lines you need to put an underscore on the previous line:

str = "a" & "b" & "c" & SOME_REALLY_REALLY_LONG_CONSTANT & _
      SOMETHING_ELSE

This makes refromatting long lines a pain. Sometimes you just end up with long string concatenations. You either have to use _'s or break up the assigment.

Classes: Bonus Hate

Let me start out by saying that it is a great thing that VBScript 5 lets you define classes. Any new level of organization is good. Even if I haven't been able to use them before since we haven't moved to Win2k yet.

Nonetheless, I've already found some things about classes that bug me.

No class consts

You can't define CONSTs as members of a class, which would have provided a way of clearing up the namespace. This means you can't write code like myThing.stuffMode = myThing.MODE_FLANGY.

Collections need not apply

You can't define methods on a VBScript class that allow it to be used via for each. This is a major bummer. I'd like to be able to use a class to hide database recordset access behind a for-eachable interface, but noooo.


As seen on the web:
Scripting News
Lambda the Ultimate
Keith Devens
Flying Chihuahuas
Techno-weenie
Tanker Town
Scottish Lass Seeks... (Um.. what? It does too have function local variables! You're using "option explicit"?)
Frogware


Contact Information