Subsections

Queues

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

ch11-2.png

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

ch11-3.png

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

ch11-4.png

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

ch11-5.png

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 REFs). 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

ch11-6.png

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.

ch11-7.png

A queue is one example of what is called a linked-list.


Exercises

11.16
Extend the queue by assigning another REF QUEUE to tail. Ans[*]
11.17
Now make tail refer to the tail of the queue again. Ans[*]
11.18
Has the name referred to by head changed after adding the new REF QUEUE? Ans[*]


Sian Mountbatten 2012-01-19