previous chapter contents page top page next chapter

HasIterator

January 21, 1993

Defined in List.Def

Mixes in with Object

Class Description

The HasIterator mixin gives its subclasses a way to call functions on each member of a group. It also defines several handy iterators itself, to perform common tasks.

Remember that if the documentation and the software (especially the definition files) disagree, always trust the software.

Using the HasIterator Mixin

You will never interact directly with the HasIterator mixin. Instead, you will use objects of classes that inherit from it and define your own subclasses using it.

Programming Information

Instantiate: never
Subclass: always
Call its methods: sometimes

Methods defined by HasIterator

Class HasIterator defines the following methods:

Method Description
Iterating
Each Call a function on each member of a group
Collect Collect members of the group that meet some criterion/criteria
CollectUnique Collect unique members of the group that meet some criteria
String matching
FindByName Find a member of the group with the given name
FindByCitation Find a member of the group with the given citation
UniqueName Return a unique name for an object, constructed by appending a number to the end of the name if there are any other objects in a group with the same name

Methods you might override

Whenever you create a subclass using the HasIterator mixin, you must override the following methods:

Method Description
Each Call a function on each member of a group

Description of fields

The HasIterator mixin defines no fields.

Method Descriptions

Iterating

Each

operation Each(proc: EachFunction; VAR params: Parameters): Object, 
noFail, noMethod

Call: often
Override: always

You must override and implement Each for all subclasses you define that inherit directly from HasIterator.

Call Each when you want to invoke a function repeatedly for every member of your subclass. If you call Each, you must also define the iterative function to be called for each list member, then pass a pointer to this function in the proc parameter. If you want to send any parameters to your iterative routine, pass a pointer to the parameters in params when you call Each.

Each keeps calling the iterative function as long as the iterative function returns nilObject and there are still objects in the list that haven't been processed. When the iterative function returns an object ID, Each stops calling the iterative function and exits. This is useful if you want to stop iterating when your iterative function fulfills some condition, such as successfully completing a search.

The routine that's called for each member of your subclass of HasIterator should be declared like this:

Private ObjectID IterativeProc (ObjectID theObject, void *params)


WARNING! You must use the Private specifier when you declare your iterative function. If you fail to do so, you'll get no warning from any tools during the build process, but your software will fail in an unpredictable way.


The theObject parameter contains the object that's currently being processed. Each passes the params parameter unchanged each time IterativeProc is called.

Here's an example of an implementation of Each, from the HasIndexing mixin:

   ObjectID     result = nilObject;
   ulong        index, count;
   if ((count = Count(self)) == 0)
      return nilObject;
   BeginImportParameters(params);
   for (index = 1; index <= count; index++)
      {
      ObjectID   object;
      if ((object = At(self, index)) == nilObject || 
          (IsObjectID(object) && !HasObject(object)))
         continue;
      if ((result = (*proc)(object, params)) != nilObject)
         break;
      }
   EndImportParameters(params);
   return result;

Collect

operation Collect(collection: ObjectList; function: EachFunction; VAR 
parameters: Parameters), noFail

Call: sometimes
Override: rarely

Call Collect to call a function on each object in a group, and add the objects returned by the function to a collection. Collect uses the Each method. The parameter collection contains the results.

CollectUnique

operation CollectUnique(collection: ObjectList; function: EachFunction; 
VAR parameters: Parameters), noFail

Call: sometimes
Override: rarely

Call CollectUnique to do the same work as the Collect method, but end up with a list without duplicates. The CollectUnique method does the same thing the Collect method does, but adds only new items to the collection, disallowing duplicates.

String matching

FindByName

operation FindByName(name: String): Object, noFail

Call: sometimes
Override: rarely

Call FindByName to search for an object with the given name in a group. The FindByName method uses the Each method to compare the name of each object in a group (the result of a GetName call) to the given name string. FindByName returns the first match.

FindByCitation

operation FindByCitation(citation: Citation): Object, noFail

Call: sometimes
Override: rarely

Call FindByCitation to search for an object with the given citation in a group. The FindByCitation method uses the Each method to compare the citation of each object in a group to the given citation. FindByCitation returns the first match.

UniqueName

operation UniqueName(VAR name: String): Boolean, noFail

Call: sometimes
Override: rarely

Call UniqueName to ensure that an object in a collection has a unique name. UniqueName appends a digit to the name if it isn't unique. UniqueName returns true if it had to change the object's name.

For example, suppose you have an object list called writerList, which looks like this:

Index Name of list element
1 Scott
2 David
3 Scott
4 Diane
5 CJ
6 Scott

Suppose you define a private iterator function as follows:

typedef struct
{
   Parameters       header;
   ObjectID         list;
} DoOneNameParams;
Private ObjectID
DoOneName(ObjectID item, DoOneNameParams *params)
{
Str255              name;
Boolean             changed;
   GetName(item, name);

   changed = UniqueName(params->list, name);
   if (changed) SetName(item, name);
   return nilObject;
}

If you then execute the following code:

SetUpParameters(&parameters.header, 1);
parameters.list = writerList;
Each(theList, (EachFunction)DoOneName, &parameters.header);

the list will look like this:

Index Name of list element
1 Scott1
2 David1
3 Scott2
4 Diane1
5 CJ1
6 Scott3