
Programming Corner from Icon Newsletter 30
June 4, 1989 ; Icon Version 7
Pointer Semantics, Graphs, and Sets
Icon uses pointer semantics for structure values. What this means is that
a list, for example, is a pointer to a collection of the values that the
list contains. A pointer, which is a memory address in implementation terms,
is small and fixed in size, even though the collection of values in the
list may be arbitrarily large.
An assignment in Icon, such as
L := list(1000)
merely copies the pointer produced by list(1000)
into L
;
the 1,000 values are irrelevant as far as the assignment is concerned --
they are not even referenced.
The use of pointer semantics has several consequences. Some are good (efficiency
in handling structure values) and some are (at least potentially) bad, such
as unintentional sharing of structure values via pointers. These issues
are discussed in the Icon language book.
What may not be obvious is how pointers to structures in an Icon program
can be used to reflect, in a natural way, structures that exist in the problem
domain. Consider, for example, a simple directed graph:

In order to perform computations on such a structure, it is necessary to
represent them in some way in a program. One way to do this is to represent
each node in the graph by a set. Then the values in the set are pointers:
arcs to the nodes to which the node points. For example, the program structures
for the graph shown above are:
A := set()
B := set()
C := set()
insert(A,B)
insert(A,C)
insert(B,B)
The important conceptual point is that a set is a pointer to a collection
of pointers to other sets. A slightly different visualization of the structures
in the programming domain illustrates this:

Thus, an arc is represented by a (pointer to) a set and a node is represented
by the values in the set.
The ease of manipulating this program representation of graphs is illustrated
by procedures to compute the transitive closure of a node (the node and
all nodes reachable from it by a succesion of arcs):
procedure closure(n)
S := set()
insert(S,n) # start with the node itself
return more(S,n)
end
procedure more(S,n)
every n1 := !n do # process reachable nodes
if not member(S,n1) then { # skip ones already in
insert(S,n1) # add new node
more(S,n1) # recurse
}
return S
end
Note that a set is used to keep track of nodes already accumulated.
There are several problems that arise in computations on graphs that may
require a somewhat more sophisticated representation of structures. For
example, if the values are associated with arcs (or if there may be more
than one arc between two nodes), the set-of-sets approach is inadequate.
In such cases, a record type can be used for arcs, as in
record arc(value,node)
where the value field contains the value associated with the arc and the
node field contains the set to which the arc points. Suppose, for example,
that the arcs in the example above are weighted:

Then the graph can be represented in the program as follows:
insert(A,arc(2.0,B))
insert(A,arc(1.5,C))
insert(B,arc(3.7,B))
Exercise: Modify the procedure closure given above to handle this
representation of directed graphs.
Two-Way Tables
Programs that manipulate graphs generally need to be able to read a representation
of a graph in string form and write results in string form. For example,
the (unweighted) form of the graph above might be represented as
A->B
A->C
B->B
Exercise: Write a procedure to read this representation of unweighted
graphs and build the corresponding program structures.
One problem is associating labels for the nodes with corresponding program
structures. The natural solution in Icon is to use a table in which the
keys (entry values) are the labels and the assigned values are the corresponding
sets. Written out explicitly for the graph above, this might be:
Node := table()
Node["A"] := A
Node["B"] := B
Node["C"] := C
Consequently, Node["A"]
produces the node (set) labelled
A
. Such a table might be used, for example, in constructing
a graph from its string representation as posed in the exercise above.
On the other hand, the converse may be needed. For example, in writing out
the results of a computation on a graph (such as the transitive closure
of a node), the labels associated with nodes may be needed.
Since any kind of value can be used as a key into a table, a table like
the one above, with the keys and entry values reversed, can be used:
Label := table()
Label[A] := "A"
Label[B] := "B"
Label[C] := "C"
It is not necessary to have two tables, however. Since the keys in a table
need not all be of the same type, the same table can be keyed with both
the labels and the nodes (sets):
Graph := table()
Graph["A"] := A
Graph["B"] := B
Graph["C"] := C
Graph[A] := "A"
Graph[B] := "B"
Graph[C] := "C"
Such a ''two-way'' table keeps all the information needed to associate labels
with nodes and vice versa in one structure. Subscript it with a label to
get the corresponding node and subscript with a node to get the corresponding
label.
Icon home page