Iterators in Details

reviewed: 22 February 2025

What are Iterators

Iterators are special CaseMaster objects that present some sort of collection that you can iterate over using the iterate - end-iterate construct.

The following shows a trivial example:

function doTest()

    iterate iterator.ofNumber( 1, 10, 'i' )
        response.write( concat( [i], ' x 7 = ', mul( [i], 7 ), '<br>' ) )
    end-iterate

    // Output
    // 1 x 7 = 7
    // 2 x 7 = 14
    // 3 x 7 = 21
    // 4 x 7 = 28
    // 5 x 7 = 35
    // 6 x 7 = 42
    // 7 x 7 = 49
    // 8 x 7 = 56
    // 9 x 7 = 63
    // 10 x 7 = 70
end-function

As you can see, iterator.ofNumber() in combination with iterate - end-iterate can be used to create the for() loop from other languages.

Another function in the iterator function handler is the iterator.ofDate() function to loop over dates:

function doTest()

    iterate iterator.ofDate( today(), addDay( today(), 7 ) , 'date' )
        response.write( concat( format( [date], 'dddd, dd/MM/yyyy' ), '<br>' ) )
    end-iterate

    // Output (when run on 22FEB25)
    // Saturday, 22/02/2025
    // Sunday, 23/02/2025
    // Monday, 24/02/2025
    // Tuesday, 25/02/2025
    // Wednesday, 26/02/2025
    // Thursday, 27/02/2025
    // Friday, 28/02/2025
    // Saturday, 01/03/2025
end-function

And iterator.ofToken() as a simple tokeniser:

function doTest()

    iterate iterator.ofToken( 'Lorem ipsum dolor sit amet' , ' ', 'word' )
        response.write( concat( [word], '<br>' ) )
    end-iterate

    // Output
    // Lorem
    // ipsum
    // dolor
    // sit
    // amet
end-function

Other types of iterators will be explained in detail in other documents; the key ones are:

Iterator Usage Covered where
iterator.ofPB Iterate over entries in a property bag Here
iterator.ofAttribute Iterate over attributes of a BO descriptor Here
iterator.ofEntity Iterate over entities; used to define queries Here
iterator.ofBO Iterate over array of BO's; used when defining forms Here

Working with Iterators

Every iterator is an object and can thus be assigned to a variable or passed as a parameter.

Check the following example:

function doTest()
    set( 'iterator', iterator.ofNumber( 1, 100, 'i' ) )

    response.write( concat( page.call( './sumIterator', [iterator] ), '<br>' ) )

    response.write( concat( page.call( './sumIterator', [iterator] ), '<br>' ) )

    // Output
    // 5050
    // 0
end-function

function sumIterator( iterator )
    iterate [iterator]
        set( 'total', add( [total], [i] ) )
    end-iterate

    return [total]

end-function

The output of the 2nd call (0) is surprising. This is because, once you have iterated over an iterator, the cursor (an internal pointer keeping track of where we are in the iterator) is pointing to the end.

The solution is to reset the iterator as following improvement:

function sumIterator( iterator )
    iterator.reset( [iterator] )

    iterate [iterator]
        set( 'total', add( [total], [i] ) )
    end-iterate

    return [total]

end-function

The iterator.count() function is used to count the number of items in an iterator:

function doTest()
    set( 'iterator', iterator.ofNumber( 1, 100, 'i' ) )

    response.write( concat( iterator.count( [iterator] ), '<br>' ) )

    // Output
    // 100
end-function

A special not on iterator.ofEntity() (see here) where iterator.ofCount() may have some unexpected side effects in special circumstances.

Another useful function is iterator.ofKey() which is especially useful when looping over entries in a property bag (see here).

<End of document>