1.20 class chain

A chain is a linear single-linked list of objects. Chains form the common way to represent collections of objects in PCE. Chains are also used to represent multiple-valued slots. Examples are device <-graphicals', class chain<-sub_classes‘, etc.

PCE chains form the natural counterpart of Prolog lists. For this reason the PCE/Prolog interface defines predicates to transform Prolog lists to PCE chains and visa-versa. Note however that in many cases it is not necessary to convert a PCE chain to a Prolog list; PCE defines many operations on chains. Before you consider converting a PCE chain to a Prolog list, first check whether it is not easier to do the job inside PCE. Notably look at chain->member, chain->empty,. chain->for_all, chain->for_some, chain<-find, chain<-find_all and chain<-map.

See also
- class vector
- class table
- class hash_table

1.20.1 Instance variables

chain-current: alien:Cell
Alien reference to current cell of the chain. The notion of current was introduced a long time ago in PCE, while methods only had one argument. Methods needing a second often used current for this purpose.

Now that PCE methods may have any number of arguments there is little use for current. It is advised not to use current.

See also
topic Current
chain-head: alien:Cell
First cell of the chain. When the chain is empty, its value is @nil.
chain <- size: int
Number of elements in the chain. Maintained by the various methods manipulating chains.
chain-tail: alien:Cell
Last cell of the chain. When the chain is empty, the slot has value is @nil and the method fails.

1.20.2 Send methods

chain ->_append: value=any|function
Append that allows for appending function objects (@arg1, @event, @receiver, class ?) to a chain without evaluating them.
See also
chain->append
chain ->add: value=any
chain->append object to chain if it is not already a member of it.
See also
- chain->member
- chain->append
chain ->after: first=any, second=any
Succeeds if the first occurrence of the first argument is after the first occurrence of the second argument. Example:
?- new(@ch, chain(aap, noot, mies)).
?- send(@ch, after, noot, aap)		--> yes
?- send(@ch, after, aap, mies)		--> no

Fails if one of the arguments is not in the chain.

See also
chain->before
chain ->append: value=any
Append argument at the end of the chain. Although chains are represented as single linked lists, append is efficient because chains maintain a pointer to the last cell.

Note that chains may contain duplicates.

See also
- chain->add
- chain->_append
chain ->before: first=any, second=any
Succeeds if the first occurrence of the first argument is before the first occurrence of the second argument. See chain->after.
See also
- chain->move_before
- chain->after
chain ->cell_value: cell_reference=int, value=any
Set the value of specified cell. The first argument is the reference returned by chain<-head_cell or chain<-next_cell.

One should try to avoid using this function.

See also
- chain<-cell_value
- chain<-head_cell
- chain<-next_cell
chain ->clear:
Remove all elements from the chain. Note that this implies that elements that have no further references are destroyed. The other elements are not affected.
chain ->current: value=any*
Replace the value of the current cell with the argument.
See also
topic Current
chain ->current_no: index=int
Make the nth (1-based) cell current. When the argument is 0, there is no current cell.

Diagnostics: Fails without modifiying the current element if the index is out of range.

See also
- topic Current
- chain<-nth1
chain ->delete: value=any
Delete the first occurrence of object from the chain. Fails if there is no such object. Note that objects are compared by their object identity; not by their contents. Hence, the following fails because the second point is a different instance.
?- new(@ch, chain(point(6,6))).
Yes
?- send(@ch, delete, point(6,6)).
No

See also chain->delete_all and chain->subtract.

See also
chain->delete_all
chain ->delete_all: value=any
Delete all elements of the chain that are equal to the argument. Always succeeds. See also chain->delete.
See also
chain->delete
chain ->delete_current:
Delete the current cell.
See also
topic Current
chain ->delete_head:
Delete the first element of the chain. See also chain<-head and chain<-delete_head.

Diagnostics: Fails if the chain is empty.

chain ->delete_tail:
Delete the last element of the chain. Note that chains are single linked lists and thus deleting the last implies traversing the entire list.

Diagnostics: Fails if the chain is empty.

chain ->empty:
Succeeds if the chain has no elements. Intended as a test method.
chain ->equal: chain
Succeeds if both chains have the same elements. For convenience reasons, the type is defined the include @default and @nil and thus this method fails silently when a chain is compared to one of these constants and fails with a type-error if the argument is neither one of these constants, nor an instance of class chain or a subclass thereof.
chain ->find: test=code
Successively executes code on all elements of the chain. Succeeds, setting chain<-current if code is executed with success. Fails otherwise. Arguments:
@arg1 The (current) element
@arg2 1-based index of element

New code should consider using chain<-find, which avoids the usage of chain<-current.

See also
- chain->for_all
- chain<-find
chain ->for_all: action=code, safe=[bool]
This method invokes its argument code object on all elements of the chain. During the execution the following argument is bound:
@arg1 Current element.
@arg2 Index of the element (1-based)

The iteration stops with failure if the execution of code fails for some element of the chain.

In the example below we print the elements of a chain on the terminal:

?- new(@ch, chain(hello, world)).
?- send(@ch, for_all, message(@pce, write_ln, @arg1)).
hello
world

If the safe argument is @on (default), the elements of the chain are first copied to a local array and existence of the objects in the elements is tested prior to executing the code object. This implies that the chain may be modified by the execution of the method and new elements will not be seen. If this argument is @off this method iterates over the chain itself. In this case it is not allowed to modify the chain.

Defaults: By default this operation is caried-out safe (= @on).

See also
- chain<-find_all
- chain<-find
- chain->find
- chain->for_some
- hash_table->for_all
- device->for_all
chain ->for_some: action=code, safe=[bool]
Similar to chain->for_all, but continues the iteration even if code fails to execute for some element. Always succeeds. Forwarded arguments:
@arg1		element
@arg2		1-based index of element
See also
chain->for_all
chain ->initialise: member=any ...
Create a chain from an initial list of elements.
chain ->insert: value=any
Insert argument before chain<-current. Use of chain<-current is discouraged and new code must consider using chain->insert_before.
See also
- chain->move_before
- topic Current
chain ->insert_after: value=any, after=any*
@see chain->move_before
chain ->insert_before: value=any, before=any
Insert first before second object. If the second object is not a chain<-member of the chain, value is chain->append’ed.

See also chain->insert_after.

chain ->member: value=any
@see chain->add
chain ->move_after: value=any, after=[any]
Move 1st object just after second. If the second object is omitted, the value is made the chain<-head of the chain.

See also chain->move_before.

See also
- chain->move_before
- node->move_after
chain ->move_before: value=any, before=any
Move the first member of the chain to be just before the second. Fails if either of the elements is not a chain->member or they are equal. To move an element to the start of the chain, you may use either of:
?- ignore(send(Ch, move_before, Element, Ch?head)).
?- send(Ch, move_after, Element).

See also chain->move_after, chain->before and chain->after.

Diagnostics: Fails silently if either argument is not a chain->member of the chain.

See also
- chain->insert
- chain->before
- chain->insert_after
- chain->move_after
chain ->sort: compare=[code|function], unique=[bool]
Sort the elements in the chain. Two elements are compared by examining the return status of the code object. Both @arg1 and @arg2 are bound to some element of the chain. Execution of the code is supposed to succeed if @arg1 must be before @arg2 in the sorted chain. If code is a function object, the return status is interpreted as follows:

chain ->subtract: chain
Delete all elements in the argument from the receiving chain. See also chain->delete_all.
chain ->unique:
Remove all duplicates from chain. Objects are compared by reference. See also chain->sort and chain->add.
chain ->unlink:
First invokes chain->clear to remove the cells.

1.20.3 Get methods

chain <-_arg: index=int -> any
@see object<-_arg
chain <-_arity: -> int
@see object<-_arity
chain <-cell_value: cell_reference=int -> any
Value associated with a cell. Use with care.
See also
- chain<-next_cell
- chain<-head_cell
- chain->cell_value
chain <-complete_name: prefix=char_array, extract_name=[function]*, ignore_case=[bool] -> tuple
Support the implementation of automatic completion as found with class text_item. The chain is a chain of elements from which one has to be chosen by means of completion. Prefix is the string typed so far. Extract_name is a function to extract the name from the each element. Its values are:
@nil Use default conversion to text.
@default Use object<-print_name.
FunctionUse this function, @arg1 is the element.

The return value is a tuple object. The tuple<-first contains a new chain holding all elements of the receiving string whose name start with the given prefix. The tuple<-second contains a new string object holding the largest common prefix of all matches. If no element of the chain matches prefix, this method fails. Example:

?- get(chain(gnu, foo, gnats, bar), complete_name, 'g',
           tuple(Matches, string(Common))),
   object(Matches, Chain).

Common = gn
Chain = chain(gnu, gnats)
Matches = @854357/chain

See also text_item->complete.

chain <-convert: vector -> chain
Convert a vector object (array) into a linked list (chain object). Because a Prolog list is translated into a code_vector object, any method requiring a chain argument can be passed a Prolog list. For example:
send(new(B, browser), open),
send(B, members, [gnu, gnat, gnome]).
chain <-copy: -> chain
Creates a copy of the chain holding the same elements in the same order.

When the receiver is a subclass of chain, the resulting chain will be an instance of the same (sub)class: an instance of this subclass is created with no arguments, after which the append behaviour of class chain is used to append the elements.

Bugs: Creating copies of subclasses is ill-defined.

chain <-current: -> any
Get the value of the current cell. Use of the current field of chains is discouraged as it makes the code non-reentrant.
See also
topic Current
chain <-current_no: -> int
Get index of the current cell. Fails if the chain has no current cell. See also chain->current
See also
- topic Current
- chain<-index
chain <-find: test=code -> any
Successively executes code on the elements. Returns the first element for which code succeeds or fails. Arguments:
@arg1 Element tested
@arg2 1-based index of element
See also
- chain->for_all
- chain<-find_all
- chain->find
- hash_table<-find_key
chain <-find_all: test=code -> chain
Returns a new chain holding all elements for which the execution of code succeeds. Arguments:
@arg1 Element tested
@arg2 1-based index of element

The following example finds all inverted graphicals on the graphical device Dev:

?- get(Dev?graphicals, find_all,
           @arg1?inverted == @on, Inverted).

See also chain->for_all.

See also
- chain->for_all
- chain<-find
chain <-head_cell: -> int
@see chain<-cell_value @see chain->cell_value
chain <-index: value=any -> index=int
@see chain<-current_no
chain <-map: function -> chain
Executes obtainer or block for each element of the chain. Returns a new chain holding the resulting values of executing the code. All elements for which the execution fails are omitted. Argument forwarding:
@arg1 Element tested
@arg2 1-based index of the element

The example below returns a chain with names holding the names of all graphical objects on the graphical device.

graphical_names(Device, Names)  :-
        get(Device, graphicals, Chain),
        get(Chain, map, @arg1?name, Names).
chain <-next: [any] -> any
Returns the element right after the given argument. If the argument is not in the chain or the argument is the last member of the chain, this method fails. If the argument occurs multiple times in the chain, the next of the first appearance is returned.

For backward compatibility only, if no argument is provided, chain<-current is returned and chain<-current is moved to the next element.

See also chain<-previous, chain<-nth1, chain<-head and chain<-tail.

See also
topic Current
chain <-next_cell: cell_reference=int -> cell_reference=int
@see chain<-cell_value @see chain->cell_value
chain <-nth1: index=int -> value=any
@see chain->current_no
chain <-previous: [any] -> any
Returns the element right before the given argument. If the argument is not in the chain or the argument is the first member of the chain, this method fails. If the argument occurs multiple times in the chain, the element before the first appearance is returned. See also chain<-next, chain<-nth1, chain<-head and chain<-tail.
chain <-sub: start=int, end=[int] -> chain
Get new sub-chain from 0-based start and end. End defaults to chain<-size. The object at chain<-end is not included. Example:
?- get_object(chain(0,1,2,3), sub, 1, 2, X).

X = chain(1)

See also char_array<-sub.