previous chapter chapter"> contents
page top
page next chapter chapter">

Linkable

June 10, 1992
last updated September 30, 1993

Defined in Foundation.Def 
Inherits from SingleLinkable, HasCount, HasIndexing


Class Description

The Linkable class provides the ability for objects to be placed in a doubly-linked list. Each linkable object includes a reference to the next and previous objects in the list. Many of the system's objects are linkable, including all viewable objects. Some of the linkable methods are widely used, especially by programs that manipulate lists.

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

Using a Linkable Object

Linkable is an abstract class that allows objects to be members of a doubly-linked list. Every linkable object refers to the next and previous objects in the list; the first element has the nil object as its "previous" link, and the last element has nil for its "next" reference.

The objects in the list are arranged so that the list is linear. That is, each object can be linked to no more than two other objects: it can be the previous object of one and the next object of another.

Note that although linkable objects are connected to form a list, there's no object that represents this list. All manipulations of the list are done by working with its elements, the linkable objects.

Programming Information

Instantiate: never
Subclass: rarely
Call its methods: sometimes

The Linkable class is abstract and you'll never directly instantiate a linkable object, or even subclass it directly. Instead, you'll probably create a subclass of one of the built-in subclasses of linkable. All viewable objects are linkable; the Linkable class implements the basic features of the view list, the list of visible objects.

You can use linkable methods to add objects to the list, remove objects from the list, or change the way the objects are connected in the list.

Many of the method descriptions for class Linkable refer to the list that an object belongs to. For example, the Remove method takes an object out of the list. Note that there isn't an object that describes this list; instead, the list is implicitly described by all the Linkable objects that point to other Linkable objects.

Methods you might call

The Linkable class has the following methods you might Call:

Method Description
AddAfter Add a new element after the object
AddBefore Add a new element before the object
AddFirst Add a new element and place it first
Count Find out the number of elements in the list
Each Perform a function for each list element
GetAt Get the object in the list at a specified position
First Get the first element in the list
Last Get the last element in the list
Next Get the list element that follows the object
Previous Get the list element that precedes the object
Remove Remove an element from the list

Description of fields

The Linkable class defines the following fields:

Field Type Description
Inherited from SingleLinkable:
next Object Next item in list
Defined by Linkable
previous Object Previous item in list

Method Descriptions

Object Management

Copy

overrides Copy

Call: sometimes
Override: sometimes

Call Copy to create a new object that's a copy of the given object. Copy also makes copies of all objects referenced by the object's fields, then sets the copy's fields to refer to the new objects. The new object is returned as the function result.

Linkable overrides Copy to clear the newly-created object's next and previous fields to nilObject. Because the next and previous fields are marked noClone in class Linkable's definition, the objects referred to by these fields aren't copied when a linkable object is cloned, so clearing these fields to nilObject doesn't leave any unreferenced objects.

You should override Copy if you want objects of your class to perform some additional processing when Copy is called.

See the description of Object_Copy for more information.

Adding to and Removing from the List

Use the methods described in this section to add elements to the list at various positions, or to remove the object from the list.

AddTo

operation AddTo(newLink: Object); noFail

Call: sometimes
Override: rarely

Call AddTo to add newLink to the object's list, in the position immediately following the object. AddTo calls AddAfter to add newLink to the list (see figure 1).

If newLink is already part of a list (that is, its previous and next fields are not both nilObject), AddTo adds the entire list that newLink belongs to, not just newLink (see figure 2).

Remove

operation Remove(oldLink: Object), noFail

Call: sometimes
Override: rarely

Call Remove to take removeLink out of its list. The list is closed up so that the remaining elements keep the list intact, as shown in figure 3. {What is it doing with the self parameter?}

Remove also correctly handles the cases of removeLink being the first or last element in the list. If removeLink is the first element, the element that was second becomes first. If removeLink is the last element, the element that was next-to-last becomes last. However, the first one now will not later be last when the list, you are a-changin'.

AddBefore

operation AddBefore(newLink: Object)

Call: sometimes
Override: rarely

Call AddBefore to add newLink to the object's list, in the position immediately preceding the object (see figure 4). If the object is the first element in the list, newLink becomes the new first element and the object becomes the second element in the list. AddBefore eventually calls AddAfter to perform its action.

If newLink is already part of a list (that is, its previous and next fields are not both nilObject), AddBefore adds the entire list that newLink belongs to, not just newLink.

AddAfter

overrides AddAfter

Call: sometimes
Override: rarely

Call AddAfter to add newLink to the object's list, in the position immediately following the object (see figure 5). If the object is the last element in the list, newLink becomes the new last element and the object becomes the next-to-last element in the list.

If newLink is already part of a list (that is, its previous and next fields are not both nilObject), AddAfter adds the entire list that newLink belongs to, not just newLink.

Many of the other linkable methods for adding objects to the list eventually call AddAfter. See the descriptions of other linkable methods for more information.

AddFirst

operation AddFirst(newLink: Object)

Call: sometimes
Override: rarely

Call AddFirst to add newLink to the object's list by making newLink the first object in the list. AddFirst calls GetFirst to determine the first element in the list, then calls AddBefore to add newLink.

If newLink is already part of a list (that is, its previous and next fields are not both nilObject), AddFirst adds the entire list that newLink belongs to, not just newLink. The first element of the list that newLink is in becomes the first element of the list that the object is in (see figure 6).

AddLast

operation AddLast(newLink: Object)

Call: sometimes
Override: rarely

Call AddLast to add newLink to the object's list by making newLink the last object in the list. AddLast calls GetLast to determine the last element in the list, then calls AddAfter to add newLink.

If newLink is already part of a list (that is, its previous and next fields are not both nilObject), AddLast adds the entire list that newLink belongs to, not just newLink. The last element of the list that newLink is in becomes the last element of the list that the object is in (see figure 7).

AddUniqueLast

operation AddUniqueLast(newLink: Object)

Call: rarely
Override: rarely

Call AddUniqueLast to add newLink as the last element in the list if newLink is not already in the list. AddUniqueLast checks to see if newLink is already a member of the object's list. If not, AddUniqueLast calls AddAfter to make newLink become the last element in the list. If newLink is already in the list, AddUniqueLast does nothing.

Getting Objects in the List

Next

attribute Next: Object
// operation Next(): Object

Call: sometimes
Override: rarely

Call Next to get the object in the list that's immediately after the object. If the object is the last element in the list, Next returns nilObject. Next simply returns the value of the object's next field.

Previous

attribute Previous: Object
//operation Previous(): Object

Call: sometimes
Override: rarely

Call Previous to get the object in the list that's immediately before the object. If the object is the first element in the list, Previous returns nilObject. Previous simply returns the value of the object's previous field.

SetNext

attribute Next: Object
// operation SetNext(nextLink: Object)

Call: rarely
Override: rarely

Call SetNext to make nextLink the element in the list immediately after the object. Any elements that were in the list after the object are disconnected from the list.

SetPrevious

attribute Previous: Object
//operation SetPrevious(prevLink: Object)

Call: rarely
Override: rarely

Call SetPrevious to make prevLink the element in the list immediately before the object. Any elements that were in the list before the object are disconnected from the list.

First

operation First(): Object

Call: sometimes
Override: rarely

Call First to get the first element in the object's list.

Last

operation Last(): Object

Call: sometimes
Override: rarely

Call Last to get the last element in the object's list.

Count

attribute Count: Unsigned, readOnly
//operation Count(): Unsigned

Call: sometimes
Override: rarely

Call Count to determine the number of elements in the object's list.

GetAt

operation GetAt(index: Unsigned): Object, noFail

Call: sometimes
Override: rarely

Call GetAt to get the object in the list at the given position. The first element in the list is at index position 1.

Assuming this list,

here are some examples:

someObj = GetAt(self, 2)  // returns object q
anObject = GetAt(self, 4) // returns self
Remove(GetAt(object_r,1)  // removes object p from the list

GetAt calls GetIndexed to perform its action.

Each

operation Each(proc: EachProcPtr; params: Pointer): Object; noFail

Call: sometimes
Override: rarely

Call Each when you want to invoke a function repeatedly for every member of the list. If you call Each, you must also define the iterative function that 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 the list 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.

The following example uses Each to make each viewable in the object's list reduce its size by 10 pixels in each dimension:

Private ObjectID
Action(ObjectID curObject, void *params)
   {
/* For each object, reduce height and width by 10 */
/* This assumes that all processed objects are viewable */
   SetContentHeight(curObject, ContentHeight(curObject)-10, true);
   SetContentWidth(curObject, ContentWidth(curObject)-10, true);
   return nilObject;
   }
Method void
HelloWorld_Shrink(ObjectID self)
{   
   (void) Each(self, Action, nil);
/* Call Action repeatedly with each element of self's list */
}

Validate

overrides Validate

Call: rarely
Override: sometimes

Linkable_Validate checks the following conditions and performs the following actions if the conditions are true:

Condition Action if true
The "next" link of the element before the Prints debug message: (object) has a bad previous:
object is not the object (object_previous)
The "previous" link of the element after Prints debug message: (object) has a bad next: (object_next)
the object is not the object

Linkable_Validate calls its inherited implementation.

You should override Validate if you want objects of your class to perform any additional validity checking. See Object_Validate for more information.