Fabulous Adventures In Coding

Eric Lippert's Blog

VBScript Default Property Semantics

Here’s a question I recently got about VBScript, where by "recently" I mean August 28th, 2003. This code works just fine:

Set myObject = CreateObject("myObject")
myObject.myName = "Eric"
WScript.Echo myObject ' myName is the default property, so prints "Eric"

But myObject = "Robert" doesn't set the default property, it sets the variable to the string. Why does reading work but writing fail? This works in VB6, why not VBScript? 

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.  The VB6 compiler can then generate the appropriate code to assign the string to the default property.

But what if you wrote a VB6 program using only variants?  When the compiler sees foo = bar typed as variants it cannot tell whether this means "set the default property of foo to bar" or "set foo to bar".  The VB compiler chooses the latter every time. VBScript is a weakly typed subset of VB -- in VBScript, everything is a variant.  So in VBScript, all assignments are treated as though the value is actually being assigned to the variable, not the default property. Therefore this is by design - this is for compatibility with VB6's behaviour.  Had we written the same program in weakly-typed VB6, we'd get the same result. 

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!  Namely, the principle that late-bound calls have exactly the same semantics as early-bound calls!" 

Indeed, as I've mentioned before, VB6 and VBScript violate this principle in several places.  Default properties were, in my opinion, a bad idea all around, for this and other reasons.  They make the language harder to parse and hence harder to understand.  In particular, parameterless default properties make very little sense in VBScript.  However, we are stuck with them now.

However, I should call out that there are some things we can do at runtime. Suppose blah is an object with a property fred that is an object, and fred has a default property which is a string. If you say foo = blah.fred then foo is assigned the default value of fred even though we lack the compile-time type information.  foo isn't set to the object fred. Of course, in this case we know to fetch the default property at runtime because we know the runtime type of fred and also know that there is no Set keyword.  These two facts are sufficient to cause the runtime engine to always fetch the default property.

Or suppose you have an object Baz with a property Table, Table has a default parameterized property Item which returns an object that has a string property Blah: Then this works just fine:

x = Baz.Table(1).Blah

But why? In this case we do not have enough compile-time information to determine that we really should call Baz.Table.Item(1).Blah.  The script engine has every reason to believe that Table is a function or parameterized property of Baz. This problem is solved by pushing it off to the implementation! The rule for implementers of IDispatch::Invoke is if all of the following are true:

  • the caller invokes a property
  • the caller passes an argument list
  • the property does not actually take an argument list
  • that property returns an object
  • that object has a default property
  • that default property takes an argument list

then invoke the default property with the argument list. Strange but true.

Perhaps unsurprisingly, not very many people know about that rule!  This is yet another reason to never, ever write your own implementation of IDispatch::Invoke.  It also leads to some mind-numbingly complex code in the VBScript IntelliSense engine that Visual Studio uses.  Making default property IntelliSense work with such a dynamically typed language was a piece of work, lemme tell ya. As I mentioned earlier, there are in fact some odd corner cases that are slightly different between VB6 and VBScript IntelliSense.  I also talked a bit about left-hand-side default property semantics earlier.

Published Tuesday, August 30, 2005 10:15 AM by Eric Lippert

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

 

Dave said:

"Default properties were, in my opinion, a bad idea all around, for this and other reasons. They make the language harder to parse and hence harder to understand."

A-men, brother.

Something that just struck me...in at least two places (default properties and With statements) VB/VBScript uses *nothing at all* in the source code to represent some important thing. This is strange because in most other places VB is liberally verbose compared to other languages.

There is dangerous potential for ambiguity when interpreting the meaning of nothing. Like when I ask my wife, "What's wrong?"
August 30, 2005 3:17 PM
 

Eric Lippert said:

Ah, but the "with" statement at least calls out "I'm doing something odd". When you see

with foo
.bar

you can just by reading the code easily figure out that this means foo.bar. The "with" statement is understandable LEXICALLY.

Default properties are different. Lexically there is nothing to show that x = y is going to call the default property of y -- this fact can only be known if you possess information about what the runtime type of y will be.

Now, that's kind of irksome, I admit. But don't forget that default properties were invented in the first place for things like collections. It really does kind of make sense to be able to say something like mycollection(98105) = "University Avenue Seattle" instead of MyCollection.Item(98105)...

Abstraction is all about hiding things. Good abstractions make plain the semantics and hide the implementation. Lots of languages hide stuff that ought to be made more plain. For example, what does this do in C#?

}

Could do anything! That brace can call arbitrary destructors, totally invisibly. Those destructors may have semantic import!


August 30, 2005 4:06 PM
 

Neyah said:

Just to be pedantic, C# doesn't have destructors. Some objects do have finalizers, but the } doesn't actually invoke them. It just allows the GC to invoke the finalizer if there are no root objects referencing those objects when the GC decides to run. Since the GC only runs when it receives pressure, this could technically be quite a while after the code in question is run.
Off the top of my head, the only time the } actually forces any type of cleanup is if you use them with a using() statement, but you are explicitly requesting .Dispose() to be called in that case.

Or did you mean to put C++ instead, and put C# there on accident since you just recently joined that team?

<TongueInCheek>
But if you're going to point out that ".bar" is easily determinable what it does by looking up to see "with foo", the same thing could be said for }. Just look up to the most recent { and figure it out.
</TongueInCheek>
August 31, 2005 6:44 PM
 

Eric Lippert said:

Yeah, I meant C++, you are correct.
August 31, 2005 11:06 PM
 

Panopticon Central said:

September 2, 2005 12:13 PM
 

Panopticon Central said:

September 2, 2005 12:20 PM
 

Gabe said:

I used to think that default properties were stupid because they necessitate a distinction between 'set' and 'let'. However, I now miss being able to say 'value = SomeControl' instead of C#'s 'if (SomeControl is CheckBox) value = (SomeControl as CheckBox).Checked.toString() else value = (SomeControl as TextBox).Text'.
September 8, 2005 3:01 AM
 

asif said:

I found this site very useful.

January 26, 2008 12:32 AM
 

Life said:

we can learn a lot about VBScript.

January 26, 2008 12:35 AM

Leave a Comment

(required) 
(optional)
(required) 
Submit

This Blog

Syndication


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