if
(T.frontonil) /*empty list*/then
begin
temp := T.front;
if
T.front = T.last /*1 elem list*/then
begin
T.front := nil; T.last := nilend
else
begin
with
(T.front)''do
if nextl = nilthen
begin
next2'".nextl := nil; next2 := nil
end
else
begin
nextl''.next2 := nil; nextl := nil
end
end;
dispose
(temp)end
end;
procedure
REV(var
T:Headcell);var
temp : ''Datacell ;begin
temp := T.last; T.last := T.front; T.front := temp
end;
function
HD(T:Headcell): Integer;begin
HD := (T.front)''.contents
end;
Remark: The expression (T. front)''.nextl = nil is evaluated often. In effect, this is a test to establish which field: nextl or next2, currently represents the "direction" of the list; i.e. when we traverse the list starting from one end, we follow either the
nextl links or the next2 links. The choice of links to follow depends on which end we
start at. A further space-time optimisation would be to allocate a variable for storing the value of the expression (T.front) ''.nextl = nil. The variable would only be updated (to another proper Boolean value) in the REV procedure because the other operations either preserve the value of the expression, or cause it to become undefined
6.6 The Efficiency of Imperative Implementations
The representation mappings between the storage graphs and the imperative languages are complex because of the nature of the Imperative language, in general, we consider the representation of a storage graph as a composition of the representation of its components; i.e. we have three kinds of representation mappings:
repn:ncol - > state, (the representation of nodes), repe: ecol ~> state (the
representation of edges), and repa; ecol ~> state (the representation of access nodes). The operations on each of these components; I.e. operations on the nodes, edges, and access nodes, can affect the program state. For example, in the
Queue
example, we specify the representation of the +1^ by:Vn:nat,N:ncol. repn(n +1^ N) =
<i(repn(N)),e(repn(N)),-f(repn(N)),
lookup(p, p bindto new(f(repn(N))) := mkdcell(n,nil) in s(repn(N))>
. For a given
ImpLang,
(a suitable enrichment ofProgram^State
by the chosen data structures) it is easy to see that the operations fromNodes&Edges'
(cf. §5.6.2.1), excepting the operations ma p t and tg rtn , can be represented by compositions (without recursion) of operations fromImpLang.
m ap t and tg-cn cannot be represented, (without recursion,) because we have no primitive operations for selecting the incoming pointers to a datacell; we can only select outgoing pointers.We conclude that if for a given object
Spec,
we can give a presentation ofSpec/SGraph
such that it contains only operations from- the object specification, - the access operations,
-
NodesSEdges',
excluding mapt and t g tn ,- the operations hd^, t l ^ , hd^, t l ^ (cf. §5.8), and
- we use the linked data structure selection method given in §6.3, then it is possible to synthesise a constant time
ImpLang
implementation.Often, we may be able to synthesise constant time implementations for specifications which do not meet these requirements. Our point is that in general, we can only predict efficient implementations when the derived operators are specified in a particular way.
In the Q u eu e example, the specification of Q u e u e /S G ra p h meets the above conditions and the example Imperative implementation runs in constant time.
In the R e v e r s i b l e _ _ L i s t _ l example, we find that the operation t g tn
occurs in part of the R e v e r s i b l e ^ L i s t _ _ l / S R e l a t i o n 5 specification which is Included in the S G ra p h Implementation. Specifically, t g tn occurs in an equation specifying the TL operation (cf. Example 5.11, §5.6.4). However, it is possible to give an alternate specification which does not Include t g tn ; namely:
Vn:nat,l:nel. TL(rep(n:l)) =
[U(n;l) hd(n:l),
(=>(n:l) \\g seen (=>(n:l) ,hd^(h:l) ) ) <hd(n:l) ,hdtl (n: 1) >]
where hdtl is a new access operator:
Vn:nat,l:nel.
hdtl(n:l) = hd(l),
We justify our chosen data structures by considering only the 1-optimised access operators, hdt 1 Is not a 1 -optimised access operator and is specified (in the language of
storage relations) by:
Vnrnat,l;nel.
hdtl(n:l) == adj (=>.(n:l) ,hd(n;l) ) .
This presentation meets our conditions and we see that our example implementation runs in constant time.
The remaining example specifications from Appendix Two conform to the conditions described above; excepting the B i n a r y _ _ T r e e examples and C i r c u l a r _ L i s t _ l e f t . The former specifications do not meet the conditions because the auxiliary " c h i l d ^ " and " c h i l d g " operations are required. The latter specification does not meet the conditions because t g tn occurs in the specification of
hdshift (shift (n : 1) ), the specification of the effect of the s h i ft operation on the
h d s hi ft access operator, (cf. Example 5.18, §5.9.1). If we do not insist that unused storage is explicitly released, then constant time implementations for the B in a r y ^ T r e e examples can be synthesised. However, we cannot give a specification
for hdshift (shift (n : 1 ) ) which conforms to the above conditions. At best, using our
method, we can only synthesise a linear time implementation for C i r c u l a r _ _ L i 8 t _ L e f t . If efficiency is crucial, then it appears that an
implementation strategy based on the storage relations is not appropriate for this specification.
6.7 Summary
In this chapter we have considered the specification of an imperative language and the choice of data structures in that language. We have described a method for choosing linked data structures; the method depends on the properties of
SGraph
and the storage type of the object specification. The specification of the language with the chosen (abstract) data structures is calledImpLang.
Two example implementations are presented in detail:
Q u e u e
andRevers ible__Li st__l.
We have described the circumstances under which constant time implementations for object specifications can be synthesised using our method. The method leads to efficient implementations for most of our example keyless specifications. For example, the implementations for