7.1 Summary
In this thesis we have considered some of the problems of implementing keyless and implicitly keyed ADTs in an Imperative programming language.
In the introduction we identified three aspects of the problem of implementing an ADT: the form of the desired implementation, the choice of implementing data structures (and the representation map between the ADT and the data structures), and the construction of the implementation. Early on, we decided to implement the primitive sort operations by pure functions and the derived sort operations by imperative procedures. So, we have concentrated on the second and third aspects: choosing data structures and constructing efficient and correct imperative procedures which use those data structures.
Our methodology for choosing the implementing data structures is based on the analysis of the algebraic semantics of the ADT. It involves partitioning the operators of the signature and defining a family of binary relations on the model of the ADT. The relations depend only on the partitioning; they are called storage relations and reflect an "observational" view of the ADT, with respect to the primitive sort. The storage relations serve as an intermediate representation of the object ADT; thus, when we define these storage relations equationally, we can consider every ADT as a specification of binary relations, or directed graphs.
In order to choose the implementing data structures, we first consider the storage relations as representations of the elements of the ADT; then, we determine which of the elements in the domains of the relations should be immediately accessible in order for the storage relations to be correct and efficient representations. These elements are called
access nodes and they are defined by access operators. Two different strategies for determining them are described. The first strategy is a general one and does not depend on the given ADT; however, the nodes thus determined are only those required for a correct implementation. The second strategy may require human intervention because it involves constructing and analysing the (partial) implementation of an object specification by its storage relations. The advantage of this method over the first is that both efficiency and
correctness determine the selection of the access nodes. A storage relation and Its access nodes comprise a storage graph. The choice of data structures and representation map depends on properties of the storage relations and storage graphs.
We have described one particular implementation strategy, in this strategy, the chosen data structure is a product, or record, consisting of a linked implementation structure and a set of entry points (the head cell) consisting of pointers thereinto. For a given object specification, the implementation is constructed in several steps and three Intermediate specifications are required:
SRelation, SGraph,
andImpLang.
The first two specifications depend on the given object specification whereas the third depends only on the chosen data structure.SRelation
is the specification of the storage relations of the object specification,SGraph
is the specification of the storage graphs of the object specification, andImpLang
is the specification of a toy imperative language which includes assignment, and pointers; it Is our target language. The implementations are constructed stepwise by enrichment. First, the object specification is implemented bySRelation,
then the resulting specification is implemented bySGraph,
and then the resulting specification is implemented byImpLang.
The final result includes an implementation of the Initial algebra of the primitive specification and it satisfies the axioms of the object specfication, but it is not necessarily an implementation of the initial algebra of the object specification.When the implementation of
Spec
bySGraph
requires only auxiliary operations taken from (a subset of) the operations ofN o d e s & E d g e s
' and {hdj^, h d ^, t i g } , then an Implementation inImpLang
can be synthesised which runs in constant time. If additional, recursively defined auxiliary operations are required in the implementation ofSpec
bySGraph,
then although an implementation can be synthesised using our method, we can not guarantee that all the operations will have constant tirhe implementations.We have described some of the circumstances under which implementations can be constructed automatically, and also when methods such as inductive inference may be used in other circumstances.
7.2 Conclusions
We have formalised some aspects of the imperative implementation of algebraically specified ADTs.
The storage relations and storage graphs of an ADT provide us with a framework: directed graphs, in which we can explore the issues of efficient implementation. Moreover, because the storage relations and graphs are algebraically specified, we can also discuss correctness within the same framework.
Our approach is a methodology rather than an algorithm, and many aspects depend on the user; for example, the relevance of the classification of an ADT by storage type depends on the definition of useful storage types. Our approach to implementation is compilation rather than Interpretation. We have found many uses for term rewriting techniques: for example, for theorem proving and inductive inference, but we have not used term rewriting for interpretation, or direct Implementation. We have not always been successful when using term rewriting techniques, but are hopeful that many of the problems encountered will be overcome.
Finally, we have demonstrated the usefulness of our approach by applying various steps of the approach to several example specifications such as
Queue, Stack
Binary^Tree, Circular_List__Right, C i rcular__List__Left,
Reversible_LiSt,
andSequence.
We have not been able to consider all of the problems associated with the implementation of algebraically specified ADTs; many topics require further investigation. We outline some of these topics in the following section.
7.3 Future Work
We have plans for future work in six areas. 1) Automation
The possibilities of automating the classification of operators, the classification of an ADT by storage type, and the synthesis of implementations using the inductive theory
of the implementation have been discussed In chapters 2, 3 and 5 resp. It seems likely that the first two theorem proving tasks may be automated. The third problem requires more research; one possibility Is to design and implement an Inductive inference algorithm based on the results of [Lan 87].
2) Analysis of ADTs
The analysis of ADTs might be Improved by considering different definitions of the storage relations and by considering a more sophisticated strategy for determining the access nodes. We could consider alternative definitions which are based on the operator classification and definitions but which also depend on other information such as priority weightings for operators and the contexts in which they appear In an algorithm. We could also investigate strategies which designate access nodes according to more sophisticated criteria. It would be interesting to compare the efficiency of the implementations synthesised using the new definitions and strategies with that of the present ones.
3) Extend the Methodology
The approach described in this thesis could be extended to include a more comprehehsive treatment of data structure selection other than the present selection of linked structures for keyless and implicitly keyed ADTs. In addition, we should consider whether and how the approach can be extended to keyed ADTs; the outcome of this investigation may well depend on how the analysis can be altered to include information about operator priorities and contexts.
4) Pretty Printing
The target imperative "code" is quite remote from the usual concrete syntax of imperative programming languages; a pretty printer which maps abstract syntax on to concrete syntax, would be very helpful when presenting the results of an example implementation.
5) Extend the Specification Language and Specify Storage Relations
We should investigate further the specification language extensions which would allow the specification of storage relations as parameterised theories. For example, we should consider equation schemas and iteration over operator symbols.