Identity versus equality

A better solution is to define equality in a way that makes sense for comparing instances of TStandardText. Comparators encapsulate the protocol of equality for many different classes of collection elements. All classes which can be placed in collections must adhere to a certain protocol. In particular, classes intended to be managed inside collections must define how they are to be compared for equality and identity. These two concepts are defined in the member functions isEqual (for equality) and isSame (for identity) for MCollectible objects. When a collection is created, the client tells the constructor whether comparison is to be based on identity or equality. If you specify NIL as the first argument to the constructor

        new TSetOf<TStandardText>(NIL, NIL); // no comparators
the collection uses a comparator based on identity. The comparator is used both to identify duplicate elements (in the case of sets) and to search for a specific object

        TStandardText *d = collection->Find(b);
If b is in collection, both d and b would point to the same object as the result of Find. Generally it makes sense to base equality on the contents of objects in collections rather than on their addresses. If that's what you want, specify a comparator (other than NIL) as the first argument of the collection constructor.

          // create comparator here
      
          TSetOf<TStandardText>* collection =
              new TSetOf<TStandardText>(comparator, NIL); // use it here
The comparator, like the collection that uses it, is created from a class template. This makes the comparator a parameterized type whose parameter is the class of elements the comparator is expected to compare.

          TComparator<TStandardText>* comparator =
              new TMCollectibleComparator<TStandardText>(); // define comparator
This last statement creates a comparator suitable for instances of TStandardText* intended to be managed as a set.

This same statement is used in the following program which properly weeds out duplicate TStandardText elements from a set where duplicates are defined by the isEqual member function of the TStandardText class.

          int main()
          {
              TComparator<TStandardText>* comparator =
                  new TMCollectibleComparator<TStandardText>();
      
              TSetOf<TStandardText>* collection =
                  new TSetOf<TStandardText>(comparator, NIL);
      
              collection->Add(new TStandardText("one"));
              collection->Add(new TStandardText("two"));
              collection->Add(new TStandardText("three"));
      
              collection->Add(new TStandardText("one"));
              collection->Add(new TStandardText("two"));
              collection->Add(new TStandardText("three"));
      
              printCollection(collection);
      
              delete collection;
              return 0;
          }
The resulting output confirms the elimination of duplicates.

      0> one
      1> two
      2> three
At this point, rather than defining comparator behavior for a specific class of elements, you are selecting among different default behaviors for comparators already provided by CommonPoint collection classes. It rare that you need to define a new class of comparator. The templatized comparators provided by the CommonPoint application system should be adequate for most classes you define for specific applications.

NOTE Comparators encapsulate a mechanism, like an API. For example many C++ objects use operator== and operator != for comparison. In addition, MCollectible objects use ::IsEqual. The CommonPoint system provides comparators to cover these cases. Only in a case where a programming organization establishes a domain-wide standard for object comparison based on IsSame is it necessary to create a new subclass of TComparator to use with CommonPoint collections. As mentioned this situation rarely occurs. It's usually easier to take advantage of existing CommonPoint comparators which user operator==, !=, <, and >.

Think of comparators as plug-in components used by collection objects. You select among different comparators to get the exact behavior you want, then plug the comparator into the collection. You don't have to define the behavior of the comparator as it determines how to perform comparisons based on a virtual function descended from TComparator::Compare.

For simple comparisons of TStandardText objects, the comparator calls TStandardText::IsEqual. The result of a call to this virtual function is an enumerated constant whose type is EComparisonResult. Generally you don't need to worry about how Compare and IsEqual work exactly, except to know that a collection uses the Compare function of a comparator which in turn invokes IsEqual (which may call IsSame) when it needs to test collection elements for equality.

Sorted sequences require a little more protocol than is provided by the TMCollectibleComparator class of comparators used by sets. Sorted sequences not only need to compare elements for equality and identity, but also must compare elements to determine if they are less than, greater than, or equal to other elements.

The class that does this is TMOrderableCollectibleComparator. In addition to the ::Compare virtual member function inherited from TComparator, TMOrderableCollectibleComparator provides a virtual member function called ::OrderedCompare. Sorted sequences invoke OrderedCompare when determining the internal order of collection elements. The elements placed in such a collection must respond to ::IsGreaterThan and ::IsLessThan messages which are sent by the comparator. In order to change the class of the collection in the previous example from a set to a sorted sequence, you would have to declare the comparator for the collection as follows.

              TMOrderableCollectibleComparator<TStandardText>* comparator =
                  new TMOrderableCollectibleComparator<TStandardText>();
Then, you would change the declaration of collection and the invocation of the collection constructor to use TMOrderableCollectibleComparator instead of TSetOf.

              TSortedSequenceOf<TStandardText>* collection =
                  new TSortedSequenceOf<TStandardText>(comparator, NIL);
The program now looks like this.

          int main()
          {
              TMOrderableCollectibleComparator<TStandardText>* comparator =
                  new TMOrderableCollectibleComparator<TStandardText>();
      
              TSortedSequenceOf<TStandardText>* collection =
                  new TSortedSequenceOf<TStandardText>(comparator, NIL);
      
              collection->Add(new TStandardText("one"));
              collection->Add(new TStandardText("two"));
              collection->Add(new TStandardText("three"));
    

    collection->Add(new TStandardText("one")); collection->Add(new TStandardText("two")); collection->Add(new TStandardText("three")); printCollection(collection); delete collection; return 0; }
The output is sorted lexically based on the contents of TStandardText objects within the collection. Since the collection is a sequence, it allows duplicate elements in contrast to a set.

      0> one
      1> one
      2> three
      3> three
      4> two
      5> two

[Contents] [Previous] [Next]
Click the icon to mail questions or corrections about this material to Taligent personnel.
Copyright©1995 Taligent,Inc. All rights reserved.

Generated with WebMaker