next up previous
Next: Calculating range expressions Up: Use of Expressions Previous: Use of Expressions

assign()/pull()

 

The assign() and pull() functions were designed to allow the modification of an element of a list, without having to delete the element from the list, shrink the list, then add the modified element back to the list. In general, assign() creates a place-holder object (an Assign object) for the element, pull() is used to release control of an object without losing its position in the list, and an assignment of a new element to the Assign object is used to put the element back in its place in the list.

The pull() method removes the specified object from its list (like grab) but maintains it's 'place' in the list. Once an object has been pulled, it is no longer possible to access the List using the pulled object as a reference. Once an object has been pulled it can be modified in any way. Once the modification is complete, the object can be returned to its position in the list by assigning to the Assign object. The user, however, is responsible for garbage collecting any intermediate forms of the pulled object which may be created. A complete use would be as follows:

        for (Mutator<Expression> expr_mutr = expr_list;
             expr_mutr.valid(); ++expr_mutr) {
                Assign<Expression> expr_as(expr_mutr.assign());
                expr_as = simplify(expr_mutr.pull());
                }

The element can also be modified as follows:

       loc = list.index(el);
       Assign<Expression> expr_as = list.assign(loc);
       expr_as = function( list.pull(loc) )

In these examples, function is simply a funtion which returns the modified value. If the modified value is a different object than the original, function is responsible for garbage collecting the original. In this case, the specified object is pulled from the list, modified somehow by function and the returned value takes it's place in the list.

The order of operations for assign() and pull() is as follows:

  1. assign() creates an Assign<Expression> which marks a Wrapper corresponding to a place in a Collection (and increments the Wrapper's reference counter).
  2. pull() takes the expression out of the Collection and leaves a marked (but empty) place in the Collection.
  3. operator = (with the Assign<Expression> on the left-hand side and an Expression * on the right-hand side) puts an expression (either the original one or a different one) into the empty place in the Collection and unmarks the associated Wrapper.
  4. the destructor for the Assign<Expression> decrements the Wrapper's reference counter.

IMPORTANT NOTE:
The current C++ standard says that for the following C++ assignment statement:

           list.assign(el) = f(list.pull(el));  // MAY BE EVALUATED INCORRECTLY

the assign() and the pull() may be evaluated in either order, assign() first and pull() second or vice-versa. This means that this assignment should not be used to accomplish a correct assign/pull operation. We have found that g++ currently calls the assign() first, which makes the operation of the above statement do the operation correctly, but there are no guarantees that this will not change in the future, and certainly other C++ compilers may use the opposite order.

The following will always be incorrect, and should not be used:

            x = list.pull(el); // INCORRECT: pull(el) evaluated before assign(el)
            list.assign(el) = f(x);

It may result in a run-time error. Or worse yet, it may not fail, hiding invalid pointers.

A similar operation can be done by using grab() and ins_first() as follows:

	Expression * expr = expr_list.grab(el);
	expr = f(expr);
	expr_list.ins_first(expr);

This involves extra Wrapper deallocation and allocation, which will be slower than the assign/pull version.

Please note that the operation involved in producing a new element may be as complicated as necessary and is not limited to a single statement as in the above examples:

	Assign<Expression> expr_as(expr_list.assign(el));
	Expression * expr = expr_list.pull(el);
	. . .  multi-step modification of expr . . .
	expr_as = expr;



next up previous
Next: Calculating range expressions Up: Use of Expressions Previous: Use of Expressions



Jay Hoeflinger
Mon Apr 21 11:52:18 CDT 1997