The name abstract type refers to a type such
that values of the type are represented in a way that is completely hidden
from users of the type. This form of information-hiding attempts to ensure
that changes to the implementation of an abstract type cannot introduce
type-errors into well-typed code that makes use of the abstract type. In
ATS as well as in many other programming languages, abstract types play a
pivotal role in support of modular programming. I will present as follows a
concrete example to illustrate a typical use of abstract types in practice.
Suppose that we are to implement a package to provide various
funtionalities on finite sets of integers. We first declare an abstract
type intset as follows for values representing finite sets of
integers:
The keyword
abstype indicates that the declared abstract type
intset is boxed, that is, the size of
intset is
the same as a pointer. There is a related keyword
abst@ype
for introducing unboxed abstract types, which will be explained elsewhere.
We next present an interface for each function or value that we want to
implement in the package:
Let us now suppose that the declaration for
intset and the
above interfaces are all stored in a file named
intset.sats (or any other legal name for a static
file).
Usually, a realistic implementation for finite sets is based on some
kind of balanced trees (e.g., AVL trees, red-black trees). For the purpose
of illustration, we give an implementation in which finite sets of integers
are represented as ordered lists of integers. This implementation is
contained in a file named intset.dats, which is
available on-line.
In order to construct values of an abstract type, we need to concretize it
temporarily by using the following form of declaration:
where
assume is a keyword. This assume-declaration equates
intset with the type
list0 (int) and this
equation is valid until the end of the scope in which it is introduced. As
the assume-declaration is at the toplevel in
intset.dats, the assumption that
intset
equals
list0 (int) is valid until the end of the file. There
is a global restriction in ATS that allows each abstract type to be
concretized by an assume-declaration at most once. More specifically, if an
abstract type is concretized in two files
foo1.dats
and
foo2.dats, then these two files cannot be used
together to generate an executable.
The rest of implementation in
intset is all standard. For
instance, the union operation on two given sets of integers is implemented
as follows:
There is also some testing code available
on-line
that makes use of some functions declared in
intset.sats. Often testing code as such is
constructed immediately after the interfaces for various functions and
values in a package are declared. This allows these interfaces to be tried
before they are actually implemented so that potential flaws can be exposed
in a timely fashion.