Consider the problem of representing a queue. We shall suppose that the queue is at a football match and that each fan in the queue has a name, in the ordinary sense, and a ticket number. Rather than just present the solution to this problem, we shall discuss the problem in detail and show why the solution is what it is.
A suitable mode for the fan would be FAN:
MODE FAN = STRUCT(STRING name,INT ticket)
but what would be a suitable declaration for a queue? At first sight, it would appear that a flexible name which can refer to a multiple of fans would be suitable:
MODE QUEUE = FLEX[1:0]FAN
but there are difficulties. Firstly, the only way a new fan could be added to the queue would be to assign a whole new multiple to a name (in the Algol 68 sense) referring to the queue:
QUEUE q; q:=q+FAN("Jim",1)
assuming that the operator +
has been declared with the header
OP + = ([]QUEUE a,FAN b)[]QUEUE:
If the queue were long, this would be very inefficient. Secondly, given a particular fan, how would we find the fan behind him or her? Knowing the subscript of the fan would seem to be the answer, but what happens if someone joins the queue somewhere in front of the fan in question? Given that there might be several fans under consideration, the program would have to update all the relevant subscripts and keep a record of which subscripts would be relevant.
The solution is to represent a queue as a recursive structure:
MODE QUEUE=STRUCT(FAN fan,REF QUEUE next)
Then a queue with two fans in it could be represented by the diagram
where the mode of each box is QUEUE and
F
and RQ
stand for FAN
and
REF QUEUE
respectively. Notice that the
next
field of the first structure refers to the structure
on its right. The next
field of the second structure
does not refer to anything.
From the declaration of the mode QUEUE
, we can see
that the next
field of the structure is a name with mode
REF QUEUE
. It would appear that it is possible to
construct a queue in the way depicted by the last diagram: each
next
field of each structure would refer to the next
structure (of mode QUEUE
) and the last next
field would have the mode REF QUEUE
and value
NIL
.
Now consider adding another QUEUE
to the right-hand
end of the queue. We immediately run into a difficulty. The value of
the next
field of the last QUEUE
is
NIL
with mode REF QUEUE
. However, we cannot
assign to NIL
, nor can we replace the
name NIL with another
name to make it refer to a new QUEUE
. The reason is that
a name of mode REF QUEUE
can only be replaced by another
name of mode REF QUEUE
if the first name is referred to
by a name of mode REF REF QUEUE
. In other words, instead
of making the structures have mode QUEUE
, we should make
them have mode REF QUEUE
. In
section 7.2, on field
selection, we pointed out that the modes of the fields of a structure
name are all preceded by a REF
. This also applies to a
recursively-defined structure. In this case, the mode of the
next
field becomes REF REF QUEUE
and could
refer to NIL
(with mode REF QUEUE
) or to
another structure of mode REF QUEUE
. We can depict this
as
where RQ
, RRQ
and RF
represent the modes REF QUEUE
, REF
REF
QUEUE
and REF FAN
respectively.
Now let us consider how such a queue could be created. Since the
length of the queue at the time the program is written is unknown (and
will change as fans join or leave the queue), it is not possible to
have an identifier for each structure forming the queue. Instead, we
can create anonymous names using a generator.
However, we must be able to refer to the queue in order to manipulate
it. Let us declare a name, identified by head
, to refer
to the beginning of the queue:
REF QUEUE head:=NIL
We have made it refer to NIL (with mode
REF QUEUE
) because the queue is currently empty. Using the
suggestion of the last section, we shall declare
REF QUEUE nilq = NIL; REF QUEUE head:=nilq
where head
has the mode REF REF
QUEUE
.
Let us assign the first fan to the queue:
head:=LOC QUEUE:=(("Jim",1),nilq)
We can represent this by the diagram
We can now assign another fan to the queue:
next OF head:=LOC QUEUE:=(("Fred",2),nilq)
Let us be quite clear what is happening here. The mode of
head
is REF REF QUEUE
. It is a name which
refers to a name so it has no fields. We can select
fields only from a QUEUE
or a
REF QUEUE
. However, the context of a
selection is weak(see
section 10.3) and so
only weak-dereferencing is allowed. Thus in
next OF head
head
is dereferenced to mode REF QUEUE
and the next
field selected (with mode REF REF
QUEUE
). The anonymous name LOC QUEUE
has mode
REF QUEUE
, so the structure display (with mode
QUEUE
) is assigned to it, and it in turn is assigned to
next OF head
without dereferencing. This means that the
nilq
which next OF head
referred to after
the first fan ("Jim",1)
was added to the queue has been
replaced by the second LOC
QUEUE
which is
what we wanted. We can now depict the queue by
We could now extend the queue by writing
next OF next OF queue:=LOC QUEUE
but since we do not know how long the queue might become, clearly we cannot go on writing
next OF next OF ...
What we need is some way of referring to the tail of the queue without
lots of selections. Because the tail of the queue always has mode
REF REF QUEUE
(it is the next
field of a
REF QUEUE
), what we need is a name of mode
REF REF REF QUEUE
(yes, three REF
s). Here
it is:
REF REF QUEUE tail;
but again we run into a difficulty (the last one). When the queue
is empty, head
refers to nilq
, but what does
tail
refer to since we cannot select from
nilq
(because it is NIL
)? The solution is to
make head
have the mode REF REF REF QUEUE
as
well as tail
and generate a name of mode REF REF
QUEUE
to refer to nilq
! (bear with it, we're
almost there):
tail:=head:=LOC REF QUEUE:=nilq
In this triple assignment, only head
is dereferenced.
We can depict this as
Now we can assign the first fan to the head of the queue:
REF REF QUEUE(head):=LOC QUEUE:= (("Jim",1),nilq))
and make tail
refer to the tail of the queue with
tail:=next OF head
in which head
is dereferenced twice, but the
selection is not dereferenced at all. The queue can
now be depicted as shown below.
A queue is one example of what is called a linked-list.
REF QUEUE
to
tail
. Anstail
refer to the tail of the queue again.
Anshead
changed after adding the
new REF QUEUE
? AnsSian Mountbatten 2012-01-19