"For Each" vs. "for in"

"For Each" vs. "for in"

  • Comments 22

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.

  • 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 ...
  • 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.

  • 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 ?
  • > 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!
  • 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 ?
  • 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.

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

Page 2 of 2 (22 items) 12