Monday, 26 December 2011

Iterator vs Enumerator in Ax 2009


Iterators Vs. Enumerators
December 13, 2011
Iterators Vs. Enumerators
We can traverse our collections by using either an enumerator or an iterator.It is a best practice to use the MapEnumerator class instead of the MapIterator class, because enumerators are automatically created on the same tier as the map (when calling the Map.getEnumerator method). Using the MapIterator class avoids a potential problem in code marked as Called from, where the iterator and map can end up on separate tiers. In addition, because map enumerators require less code than map iterators, they perform slightly better. The only situation where you have to use a map iterator, is when you want to delete items from a list (use the MapIterator.delete method).
.Simply what we do is that just replace iterator with the enumerator.

First theoretically what happens behind the scenes is as follows:

When collection classes were first introduced in DAX, the iterator was the only option.But because of a few unwarranted drawbacks that appear as hard-to-find errors, enumerators were added, and iterators were kept for the backward compatibility. Just see the below listed code snippet

List list   = new List(Types::Integer);
ListIterator  iterator;
ListEnumerator  enumerator;
;
//Populate List
…..
…..

//Traverse using an iterator.
iterator = new ListIterator(list);

while(Iterator.more())
{
print iterator.value());
iterator.next();
}

//Traverse using an enumerator
enumerator = list.getEnumerator();

while(enumerator.moveNext())
{
print enumerator.current();
}

The 1st difference is the way iterator and enumerator instances are created.For the iterator,you call new,and for the enumerator,you get an instance from the collection class by calling the getEnumerator method.

In most cases, both approaches will work equally well. However, when the collection class resides on the opposite tier from the tier on which it is traversed,the situation is quite different.

For example, if the collection resides on the client tier and is traversed on the server tier, the iterator approach fails because the iterator does not support cross-tier referencing.

The enumerator does not support cross-referencing either, but it doesn’t have to because it is instantiated on the same tier as the collection class. Traversing on the server tier using the client tier enumerator is quite network intensive, but the result is logically correct because some code is marked as “Called From”, meaning that it can run on either tier,depending on where it is called from. You could have broken logic if you use iterators, even if you test one execution path.In many cases, hard-to-track bugs such as this surface only when an operation is executed in batch mode.

The 2nd difference is the way traversing happens which is another potential threat as the onus lies on the developer to ensure that he moves the pointer by using .next() method else the code can land into endless loop.So again enumerator is clear winner here

But there is still one scenario while iterator holds edge over enumerator, if you want to delete/insert items from list.See the code snippet below:

List   list = new List(Types::Integer);
ListIterator iterator;
;

list.addEnd(100);
list.addEnd(200);
list.addEnd(300);

iterator = new  ListIterator(list);
while(iterator.more())
{
if(iterator.value() == 200)
iterator.delete();
iterator.next();
}
print list.toString();   //{100,300}
pause;
}

1 comment: