Fabulous Adventures In Coding

Eric Lippert's Blog

"For Each" vs. "for in"

While we're on the subject of semantic differences between seemingly similar syntaxes, let me just take this opportunity to quickly answer a frequently asked question: why doesn't for-in enumerate a collection?

A VB programmer is used to this printing out every item in a collection:

For Each Item In MyCollection
    Print Item
Next

VB programmers introduced to JScript always make this mistake:

for (var item in myCollection)
{
    print(item);
}

and they are always surprised when this prints out a bunch of unexpected strings, or perhaps nothing at all.

The difference is quite simple.  In VBScript, For Each enumerates the members of a collection. In JScript, for in enumerates the properties of an object. In JScript if you have

var foo = new Object();
foo.bar = 123;
foo.baz = 456;

then you can enumerate the properties:

for (var prop in foo)
    print (prop + " : " + foo[prop])

JScript needs such a control flow structure because it has expando objects and sparse arrays. You might not know all the properties of an object or members of an associative array. It's not like VBScript where objects have fixed members and arrays are indexed by dense integer tuples. VBScript doesn't need this ability, so it doesn't have it.

Incidentally, in order to implement the JScript for in loop we needed to extend the functionality exposed by a dispatch object. Hence IDispatchEx, which gives the caller the ability to enumerate dispids and go from dispid back to name.

In JScript to enumerate members of a collection, use the Enumerator object:

for (var enumerator = new Enumerator(myCollection) ; !enumerator.atEnd(); enumerator.moveNext())
{
    var item = enumerator.item(); 
    // ...

The reaction I get from people who have not seen object-oriented enumerators before is usually "yuck!" This is an unfortunate reaction, as enumerator objects are extremely powerful. Unlike lexical For Each loops, enumerators are first-class objects. You can take out multiple enumerators on a collection, store them, pass them around, recycle them, all kinds of good stuff.

The semantics of the for in loop in JScript .NET are kind of a hodgepodge of both styles, with several interesting extensions. First off, if you pass an enumerator object itself to the JScript .NET for in loop, we enumerate it. If the argument is a JScript object (or a primitive convertible to a JScript object) then we enumerate its properties as JScript Classic does. If it is a CLR array, we enumerate its first dimension indices. If it is a collection, we fetch an enumerator and enumerate that. Otherwise, you've passed a non-enumerable object and we throw an exception

UPDATE: The sequel to this entry can be found here.

Published Monday, September 22, 2003 2:19 PM 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

 

Blake said:

Mmm, so JScript.NET is in scope for questions too?
September 22, 2003 3:25 PM
 

Eric Lippert said:

Sure. I mean, I'm no Peter Torr, but I know a thing or two about it.
September 22, 2003 3:52 PM
 

Ajay [MVP.NET] said:

Eric..your article displays the common mistake done by most of the VB Programmers (includes me) when moved to JScript. I had a similar problem ;). I liked this article. Probs you can also write an article on the common mistakes done by the VB programmers migrating to VB .NET
September 23, 2003 5:23 AM
 

Eric Lippert said:

Though I was for a time on the VB .NET design committee, and implemented a very small portion of the VB.NET IDE, I actually do not know much about the practical ins and outs of the language compared to some people around here! The page you want to read is my colleague Paul Vick's blog. Go to http://www.panopticoncentral.net -- he invites questions about the design of VB .NET. He can give you a lot better information than I can.
September 23, 2003 11:42 AM
 

Jay said:

Instead of the for/in syntax, I've been using one that takes advantage of anonymous functions and closures: enumerate( collection, function( item ) { WScript.echo( item ); } ); Where: function enumerate( coll, f ) { for( var en = new Enumerator(coll); !en.atEnd(); en.moveNext() ) { f( coll.Item() ); } } The actual function also enumerates arrays & objects.
November 5, 2003 1:27 AM
 

Chris said:

God bless you. This was my first stop to google for a solution.
March 31, 2004 10:31 PM
 

Eric Lippert said:

You're welcome; I live to serve. :-)
March 31, 2004 10:43 PM
 

Jason said:

"then you can enumerate the properties:

for (var prop in foo)
print (prop + " : " + foo[prop]) "


...So close to what I need. Is there a VBScript syntax that performs the same duty as the listed JScript syntax, i.e. enumerating the properties of an object when the property names are not known beforehand?
April 1, 2004 12:51 PM
 

Eric Lippert said:

Which part of "VBScript doesn't need this ability, so it doesn't have it. " was unclear?

:-)

What's the scenario where you have an object in VBScript but don't know the properties?
April 1, 2004 1:00 PM
 

Jason said:

When the reference materials aren't clear / are difficult to find.

In particular, what I'm working on now is a tool to display group membership. We have a single-domain forest that trusts an external domain. Some of our groups contain users from this external domain.

In code, I connect to one of our computers, enumerate the groups, and use Group.Members to enumerate the users in the group. Then, I display several properties for that user as follows:

strComputer="."
Set colGroups = GetObject("WinNT://" & strComputer & "")
colGroups.Filter = Array("group")
For Each objGroup In colGroups
WScript.Echo objGroup.Name & " members:"
For Each objUser in objGroup.Members
If objUser.Class = "User" Then
WScript.Echo objUser.Name & objUser.Fullname & objUser.Description
End If
Next
Next

I'm not certain what kind of object objGroup.Members is returning, so I don't _really_ know what properties/methods objUser supports. I would guess this kind of situation would come up fairly often, when you're working with someone else's objects.

This code shows information for both users from the local domain and from the trusted domain, but I don't know of a clear way to display whether the user belongs to my domain or to the trusted domain. If I could get a list of properties and/or methods that are valid for my objUser, I'd at least have a clue where to begin.

April 1, 2004 1:46 PM
 

Eric Lippert said:

The problem is that the object has to be specially written in order to determine what its properties are AT RUNTIME. JScript objects are written that way, most objects are not. That's why VBScript doesn't have this feature -- it is only useful for JScript objects and the browser object model.

If you want to determine what "static" methods an object supports, you can write a C++ program that queries the type information, either by statically analyzing the type library on disk, or by calling the live object via IDispatch, obtaining its type information, and walking that.

However, not every object is guaranteed to provide type information at run time.

Stay tuned -- I may someday do a blog entry on how to dynamically and/or statically read type information about an object.
April 1, 2004 1:49 PM
 

Jason said:

Thank you, I'll be anxiously awaiting it...it would be a real timesaver for those of us who can't always get access to good documentation.
April 1, 2004 2:06 PM
 

The Old New Thing said:

April 21, 2004 1:31 PM
 

Fabulous Adventures In Coding said:

October 7, 2004 1:34 PM
 

Adam Ralph said:

Thanks very much for this blog entry. It gave me exactly the info I was looking for.
October 21, 2005 7:44 AM
 

Till said:

Many thanks for all of those informations.

However, I'd like to go back to Jason's question. I have similar needs, and I know now I can acheive it with JScript (thaks to you).

Let say I have an object "MyObject" that have the properties "height", "width" and "depth".
If I want to write a function that addresses only one of these properties at a time, a JScript code would look like :
function treatDimension(selDim)
{
<action on > MyObject[selDim]
}

how can I write such a code in VBScript ?
buy now, one solution is something like :
Function treatDimension ( selDim)
   Select Case selDim
        Case "height"
                <action on > MyObject.height
        Case "width"
                <action on > MyObject.width
        Case "depth"
                <action on > MyObject.depth
   End Select
End Function

of course, I'd like to avoid such a "select case" statement, since the actual code might grow much more complicated.
I'm desperately browsing the web for such a solution, but I have hard time to find it yet ...

Hope you have an answer to it ...
March 19, 2006 9:55 AM
 

Eric Lippert said:

The switch statement version is pretty much the best you can do in VBScript.  There is a gross way to do what you want which is

function treatDimension ( selDim)
      Execute "<action on > MyObject." & selDim
End Function

However, this is incredibly dangerous if you cannot guarantee that the caller is only going to pass in sensible strings.  If selDim happens to be "height: codetodeleteyourharddisk()"  then that's what's going to run.  I would avoid such a situation if at all possible and stick with the safe, easy-to-understand select statement if you have to do this in VBScript.

March 21, 2006 1:29 PM
 

Till said:

Many thanks for your answer I'll try it anyway.

Why is there such a difference in both languages ?
It happens so many time, for me, that I needed to "parametrize" the name of methods or proprieties.

In fact, as long as I understand it clearly, what I'd like to have is a sort of "scripting layer" that would resolve property names only at run time, which is somewhat what your "execute" tip is doing.

I was more looking for a syntaxic approach, with escape characters or whatever (similar to JScript).
<action on> MyObject.[`selDim`] for instance, or else
Do you think we can expect such enhancements in the future ?
March 22, 2006 6:42 AM
 

Eric Lippert said:

> Why is there such a difference in both languages ?  

VBScript and JavaScript were invented by different people at different companies at different times to solve different problems, so it should not be surprising that the languages are in many ways different.

> Do you think we can expect such enhancements in the future ?

No new features have been added to VBScript in about six years now, so I wouldn't hold my breath waiting if I were you!
March 23, 2006 1:51 PM
 

Till said:

Hmmm.
> VBScript and JavaScript were invented by different people at different companies at different times to solve different problems, so it should not be surprising that the languages are in many ways different.

Of course.
My guess is that they both try to finally cover user's needs that can be araised during their use.

Don't you think those needs make any sense ?
March 23, 2006 4:46 PM
 

Gary D. said:

I have read and re-read this blog entry, trying to make sense of the first line of the 4th to the last paragraph. It reads "In JScript to enumerate properties of an object, use the Enumerator object...".  Should it not read "In JScript to enumerate members of a collection, use the Enumerator object...".

A few lines earlier you wrote  "In JScript, [the "]for in[" syntax] enumerates the properties of an object. " which would make the enumerator object unneeded for that purpose. The problem that got the blog entry started was people used to using vb trying to use "for in" in jscript to enumerate members of a collection so it would seem logical that this code snippet would address their need.  If I am correct, do you have the ability to fix the blog and delete this comment?

I always hate being confused by something and then having to search the comments to see if it has been adressed or not.  It would be much easier to just revise the content when the issue was discovered.

December 20, 2007 9:56 AM
 

Eric Lippert said:

Your analysis is correct. I've fixed the error. Thanks!

December 20, 2007 11:29 AM

Leave a Comment

(required) 
(optional)
(required) 

  
Enter Code Here: 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