“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 JavaScript 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 JavaScript, for-in enumerates the properties of an object. In JavaScript 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]) 

JavaScript 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 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 an object (or a primitive convertible to an 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.


There were a number of good responses to this article:

I like that you showed a common mistake of VBScript developers moving to JavaScript; what about VBScript developers moving to VB proper? What mistakes to they commonly make?

The advice I gave to the reader was to read Paul Vick’s blog, www.panopticoncentral.net I’m pleased that Paul is still blogging all these years later!

Here’s a clever trick for doing enumeration by passing in a function. We make a helper function, and then call it with the function to execute on each item:

function enumerate( coll, f )
{
  for( var en = new Enumerator(coll); 
    !en.atEnd(); 
    en.moveNext() )
  {
    f( coll.Item() );
  }
}
... 
enumerate(collection, function(item) { ... });

Though that is slick I am generally not that big a fan of mixing functional and imperative programming in cases where there’s an existing language construct that does the job.

I do sometimes need the ability to iterate property names in VBScript because it is often unclear what the properties of an object are; not all objects are well-documented.

The problem is that a lot of OLE Automation objects do not expose a mechanism for doing so; it can be tricky to go from an instance of an object to its type information.

Why are VBScript and JavaScript different in this regard?

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.

Can we expect any enhancements to VBScript in this area?

We stopped adding new features to VBScript in 2001, so, I would not expect anything, no.

 

1 thought on ““For Each” vs. “for in”

  1. Pingback: Porting old posts, part 2 | Fabulous adventures in coding

Leave a comment