Name

Collection - supertype of all collection types


Synopsis

//
// Collection -- supertype of all collection types
//
@deftype Collection <Create, SetInitialValue, Copy, Drop>
CREATING
- (void)	setMemberType: aDataType;
- (void)	setIndexSafety: indexSafety;
- (void)	setIndexUpdateHandler: (func_t)handler : (void *)arg;
- (void)	setReplaceOnly: (BOOL)replaceOnly;
USING
-		getMemberType;
-		getIndexSafety;
- (func_t)	getIndexUpdateHandler: (void *)arg;
- (BOOL)	getReplaceOnly;

- (int)		getCount;

-		atOffset: (int)offset;
-		atOffset: (int)offset put: anObject;

-		getFirst;
-		getLast;

- (BOOL)	contains: aMember;
-		remove: aMember;
- (void)	removeAll;

-		begin: aZone;

- (void)	forEach: (SEL)aSelector;
- (void)	forEach: (SEL)aSelector : arg1;
- (void)	forEach: (SEL)aSelector : arg1 : arg2;
- (void)	forEach: (SEL)aSelector : arg1 : arg2 : arg3;
@end

Description

A collection is a grouping of object references or other data values which are assigned explicitly as members of the collection. Depending on the subtype, collection members may also be maintained in various associations with each other, such as an ordering of members or an association of members with identifying key values. Major Collection subtypes include Array, List, Set and Map. The Collection supertype establishes common conventions (and associated messages) supported by all types of collections.

All collections support traversal over their members using a separate object called an Index. All collections also follow common rules regarding the types of data values which may be added as members. The next two subsections summarize these basic features of all collections.

Index objects

An index is a special type of object that references a current position in an enumeration sequence over a collection. An enumeration sequence contains every member of a collection exactly once. Every collection defines an associated type of object for its index. The index type of a collection defines additional ways in which the members of a collection may be processed beyond any messages available directly on the collection. Often the operations of an index provide the most basic and flexible means for manipulating individual members of a collection. An index object into a collection may be created at any time. An index is the basic means to traverse through all members of a collection. Multiple indexes on the same collection may all exist at the same time and may reference the same or different positions. Depending on the collection type, it may be possible to modify a collection through its indexes.

Once an index is created, the sequence of members in its enumeration sequence is guaranteed to remain the same, provided that no new members are added to the underlying collection, or existing members removed. If a member is located once at a particular position, it is guaranteed to remain at that position as long as the index itself remains.

Many collection types define an explicit ordering over their members. For such collections, the sequence of members referred to by an index will always be consistent with this ordering. An explicit, total ordering also guarantees that all indexes of the same collection have the same member sequence.

If no such ordering is defined, however, some particular sequence of all the collection still becomes associated with each created index. All collection members are guaranteed to be contained somewhere in the enumeration sequence for any particular index, but two indexes on the same collection are not guaranteed to have the same sequence.

The Index type corresponds to the iterator types defined as part of many other object-oriented libraries. The name Index is shorter and emphasizes the more abstract and multi-function role of these basic support objects for any collection. For more background on design of indexes and iterators, see the Interface Design Notes for the collections library.

Member types

The default member type of any collection is the id type defined by Objective C. All messages which add, remove, or access members declare their member value with the id type. None of the collection types, however, requires that the member value actually point to a valid object. The member values of any collection may contain an arbritrary bit pattern, provided these bits fit in the space available within an id pointer.

global portability assumptions, the number of bits in an id value may be safely assumed to be at least as large as an int (signed or unsigned), but not necessarily as large as a long.

There is also an option to override the default member type so that it can be larger than a id pointer. Use of this option, however, changes the way member values must be passed to or from a collection. More information is given with the MemberType option below.


Inherited behavior

@deftype Collection <Create, SetInitialValue, Copy, Drop>
(.. SetInitialValue and Copy behavior is currently implemented for Array and List, but not for Set or Map.)

The Collection type inherits standard messages from the defobj library for creating and customizing objects. These messages are defined as part of the defobj Create supertype. The only collection types which are directly creatable, however, are those directly tagged as such (with the CREATABLE type tag).

In addition to the standard create messages inherited from the defobj Create supertype, Collection inherits the SetIntialValue, Copy, and Drop types (also from defobj). Copying or dropping a collection has no effect on objects which might have be contained in a collection as members; only the references to objects contained in the collection are copied or freed.

SetInitialValue defines special create messages to load the initial members of a newly created collection from an existing collection, and optionally to make the members of a collection read-only after this initialization. If the members of a collection are read-only, all collection messages which add, replace, or remove members will raise an InvalidOperation error. Even if a collection was not initially created with ReadOnly status, this status may also be set later. If a collection is created with the ReadOnly restriction set, however, this restriction cannot later be unset.

A collection used as an initial value need not have the same type as a collection being created. Members (and keys, too, if applicable) are added to the new collection in the same order as defined by traversing the initial value collection with a local temporary index. Create-time options are also applied as noted under SetInitialValue. Some collection subtypes may have further special rules for initial values; if so, these are documented with the subtype.

[aCollection copy: aZone] is equivalent to [[aCollection getType] create: aZone setInitialValue: aCollection].


Create-time options

CREATING
- (void)	setMemberType: aDataType;
- (void)	setIndexSafety: indexSafety;
- (void)	setIndexUpdateHandler: (handler_t)handler : (void *)arg;
SETTING
- (void)	setReplaceOnly: (BOOL)replaceOnly;
USING
-		getMemberType;
-		getIndexSafety;
- (handler_t)	getIndexUpdateHandler: (void *)arg;
- (BOOL)	getReplaceOnly;

MemberType

(.. This option is not currently implemented for any collection types.)

The MemberType option may be used to declare the type of member which a collection contains. Its value must be an objec having one of the ValueType types defined in defobj. (..Currently no ValueType objects are implemented, so MemberType is not supported.)

The member type defaults to the Symbol value Unknown. Specifying a member type has no effect on the collection if the storage size of the data type is no larger than a pointer of id type. The member type, however, may be helpful as documentation, and members can be checked for conformance to the type as part of debug options. If the data type has a size greater than id, the collection automatically allocates and frees space for the member value whenever member values are added or removed. For such a collection, all member values must be passed to the collection not as the value itself, but as a pointer to the value (cast to id as necessary). If a new member is being added, the value will be copied to a new member location contained within the collection. Member values returned by the collection will be returned as pointers to this internal value, not as the value itself. In the case of member values removed from the collection, a nil pointer is returned.

IndexSafety

(.. This option is not currently implemented for any collection types.)

The IndexSafety option has one of the following values:

id   Unsafe, UnsafeAtMember, SafeAlways;
If not specified, the default value depends on the specific collection subtype. In typical cases, the default value is Unsafe. A non-default value is required for indexes to have a guarantee of safety when independent modifications to the underlying collection are also performed.

Without a guarantee of index safety, the effect of any operation which modifies the underlying collection (adding, removing, or replacing members) could be to disrupt the position assumed by any existing index. The effect of such disruption is, in general, completely unpredictable: it could be an immediate crash, a wrong sequence of members, or other difficult-to-debug conditions. To avoid such unpredictability, several means for assuring the safety of indexes under independent collection update are provided.

The simplest way to guarantee index safety is to set the IndexSafety option to the value SafeAlways when a collection is created. With the value of SafeAlways, any active index on the collection will be updated automatically to reflect any change to the underlying collection whenever such a change occurs. This automatic update continues to occur throughout the lifetime of any index on the collection; it ceases to occur only after an index is dropped. This is the easiest option to use, but consumes extra resources to accomplish (both time and space within the collection), so is most suitable when the extra resource usage deesn't matter or there's no better way.

With an IndexSafety value of SafeAlways, there is also an additional option to declare an external index update handler. The handler is specified using the setIndexUpdateHandler:: message. If an IndexUpdateHandler is specified, the value for IndexSafety is also automatically set to SafeAlways.

The first argument of setIndexUpdateHandler:: specifies a function which is called whenever a modification to the underlying collection occurs which could require an update to existing indexes. The second argument establishes a pointer value which the handler function may use to identify the indexes which need to be updated, or any other information needed for the update.

(.. Exact call conventions for the IndexUpdateHandler are still being established, but the activity library will soon be converted to use this technique, so the conventions will be resolved during that conversion.)

Besides the extreme values of Unsafe and SafeAlways, another valid value for IndexSafety is UnsafeAtMember. This value indicates that the only modification of the collection which could disrupt existing indexes is to remove the member contained at the current index position, or to change the member on either side of an index positioned between members. For some collection subtypes, this level of safety is automatically assured, and for others it can be requested with less overall resource impact than SafeAlways.

ReplaceOnly

(.. This option is not currently implemented for any collection types.)

This boolean-valued option restricts valid usage of a collection by excluding all operations which add or remove members. For some collection subtypes, a replace-only restriction can obtain many of the same performance advantages as a read-only collection, but without disabling replace operations as well. Just like the ReadOnly option, the ReplaceOnly option may be reset after a collection is created, provided it was not originally set to true.


Collection behavior

- (int)		getCount;
getCount returns the integer number of members currently contained in the collection. All collections maintain their count internally so that no traversal of collection members is required simply to return this value.

-		atOffset: (int)offset;
-		atOffset: (int)offset put: anObject;

-		getFirst;
-		getLast;
An offset is an integer value that gives relative position of a member in the enumeration sequence of a collection. Offsets start the count of the first member at zero, just like C array indexing.

Offsets provide an alternate means to access the members of a collection, without creating a separate index object. Some collection subtypes (such as Array) support fast, direct access by integer member offset, while others support member offsets only as a shorthand for sequential access through every preceding member. Access by offsets is supported on all collections regardless of whether its speed on a particular collection type.

The atOffset: message returns the member at a particular member offset. The atOffset: put: message replaces the member at a particular offset with a new value, and returns the previous member value at this offset. Both these messages raise the error OffsetOutOfRange if the offset is less than zero or greater than or equal to the count of members in the collection.

The getFirst message is equivalent to [aCollection atOffset: 0], and the getLast message is equivalent to [aCollection atOffset: [aCollection getCount] - 1].

- (BOOL)	contains: aMember;
-		remove: aMember;
- (void)	removeAll;
The contains: message returns true if the collection contains any member value which matches the value passed as its argument. Depending on the collection subtype, this may require traversing sequentially through all members of the collection until a matching member is found. For other subtypes, some form of direct indexing from the member value may be supported. The message is supported regardless of its speed.

The remove: message removes the first member in the collection with a value matching the value passed as its argument. If there is no such member, a nil value is returned. As with the contains: message, the speed of this operation may vary from very low to linear in the number of members, depending on the collection subtype.

The removeAll message removes all existing members of a collection and sets its member count to zero. The collection then remains valid for further members to be added. This message has no effect on the objects which might be referenced by any removed member values. If resources consumed by these objects also need to be released, such release operations (such as drop messages) can be performed prior to removing the member values.

-		begin: aZone;
The begin: message is the standard method for creating a new index for traversing the elements of a collection. All further information about indexes is documented under the Index type.

- (void)	forEach: (SEL)aSelector;
- (void)	forEach: (SEL)aSelector : arg1;
- (void)	forEach: (SEL)aSelector : arg1 : arg2;
- (void)	forEach: (SEL)aSelector : arg1 : arg2 : arg3;
The forEach messages supply a convenient shorthand for repeatedly performing the same message on all objects contained as members in a collection. The message to be sent is identified by the argument aSelector. This selector must define the same number of arguments as contained in any remaining argument slots of the forEach message. The argument types of the message to be sent must be either the id type, or some other type that will fit in the same number of bits as the id type. By global portability assumptions, the argument type could be as large as an int (signed or unsigned), but not necessarily as large as a long. To use the message, any non-id value must be cast to the id type as part of the call expression.

The forEach: messages are implemented by a simple loop through all members of a collection, using an internal, temporary index. If any operation more complex than a simple message send is required, this operation should just be coded directly using a loop that traverses its own index.


Roger Burkhart <rmb@santafe.edu>
Last modified: