Specification of the ADT "simple list of integers" and
implementation in a Pascal-like language.
Specification
In an abstract sense, a list is a sequence of "nodes",
where each node contains an information (an integer number in this case).
"Simple" here means that the only operations of the ADT are:
- the creation of the empty list, i.e. the list with 0 nodes (emptylist),
- the test whether a list is empty (is_empty),
- the addition of a new node in front of a list (cons),
- the access to the information in the first node (head),
- the list obtained by removing the first node (tail).
The type of each operation
(interface) is specified as follows:
- emptylist: () -> list
- is_empty: (list) -> boolean
- cons: (integer,list) -> list
- head: (list) -> integer
- tail: (list) -> list
where f: () -> T means that f has 0 arguments and result of type T,
f: (T1) -> T2 means that f has 1 argument of type T1 and result of type T2,
etc.
Implementation
The implementation of an ADT consists of two parts:
- concrete representation of the elements of the new type
in terms of existing types,
- definition of the operations as functions or procedures
Representation of lists
One possible approach to the concrete representation of lists
is by using records and pointers.
type list = ^element;
element = record
info : integer;
next = list
end;
Definition of the operations
function emptylist : list;
begin
emptylist := nil
end;
function is_empty(L:list): boolean;
begin
if L = nil then is_empty := true else is_empty := false
end;
function cons(x:integer, L:list): list;
var aux : list;
begin
new(aux);
aux^.info := x;
aux^.next := L;
cons := aux
end;
function head(L:list): integer;
begin
if L = nil
then head := 0 /* error */
else head := L^.info
end;
function tail(L:list): list;
begin
if L = nil
then tail := nil /* error */
else begin
tail := L^.next;
dispose(L)
end
end;
Using the ADT "simple list"
A correct use of the ADT should use only the
operations of the interface, i.e. emptylist, isempty, cons, head and tail.
For instance, consider below two possible definitions of the append
function: The first respect this principle, the second doesn't.
Of course, if the language offered a mechanism to protect the
ADT, the second could not even
be written.
"Good" append (implementation-independent)
function append(L1,L2:list): list
begin
if is_empty(L1)
then append := L2
else append := cons(head(L1),append(tail(L1),L2))
end;
"Bad" append (implementation-dependent)
function append(L1,L2:list): list
begin
if L1 = nil
then append := L2
else append := cons(L1^.info,append(L1^.next, L2))
end;