[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Proposal: Abstract types for OOC



Folks,

Following the earlier discussion, here is a proposal for abstract types for
OOC. I've tried to cover all the relevant issues. Does anyone have anything
to add or change?


Abstract types for OOC

Abstract types allow the behaviour ("methods") of a type to be specified
without defining the implementation of this behaviour. Abstract types
contain declarations for type-bound procedures. The implementation for
these procedures is defined by concrete sub-types.

The Oberon-2 language lacks a framework for abstract types. These must be
simulated using concrete types. HALT statements are traditionally used in
the body of "abstract" methods, so that a run-time exception will result if
an abstract method is called. This is not a safe way to solve the problem.
To preserve the semantics of abstract types, we can reasonably expect the
compiler to:

1) Allow the programmer to differentiate between abstract and concrete
types in declarations.
2) Prohibit the instantiation of abstract types.
3) Prohibit the calling of abstract methods.
4) Ensure that concrete types implement all the required abstract methods.

This specification proposes an extension to the OOC compiler which will
support these essential features. The framework requires no changes to the
Oberon-2 language itself. The ABSTRACT system flag can be applied in
procedure and type declarations. Compilers that do not recognise the flag
will ignore it and compile the code as normal. Since the ABSTRACT flag
only restricts allowed behaviour and does not introduce new functionality,
code that compiles correctly using the OOC abstract types model should run
correctly anywhere else. Other Oberon systems will allow the abstract types
to be instantiated, but this can probably be avoided by providing
appropriate constructor procedures within the defining modules.

Definitions:

"Methods" are type-bound procedures. A "concrete method" specifies an
implementation. An "abstract method" gives a procedure declaration, but not
the actual implementation. Abstract methods are forward declarations for
methods that will be implemented by sub-types.

An "abstract type" is a record type that has some abstract methods. A
"concrete type" is a record type that has only concrete methods.

Abstract Type Declarations:

Both types and methods may be declared abstract using the ABSTRACT system
flag. For example:

TYPE
  (* Declaration of abstract type *)

  a* = RECORD [ABSTRACT]
    x-, y- : REAL;
  END;

  PROCEDURE [ABSTRACT] (VAR v : a) F * (x, y : REAL);
  BEGIN
  END F;

A type or method that is not declared ABSTRACT is assumed to be concrete.
Strictly, the body of an abstract method is not required : it can never be
called. However, abstract methods MUST BE declared with a normal procedure
body. This means that the declaration will still be accepted by compilers
that do not implement the ABSTRACT feature.

The following rules apply to abstract types:

1) An abstract type can never be instantiated. The type cannot be used for
variables, record fields or the NEW procedure.

2) All abstract types are extensible. The tag NOT_EXTENSIBLE cannot be used
in combination with ABSTRACT.

3) A record type MAY BE declared ABSTRACT providing it does not extend a
concrete type. That is, a type may be abstract if it extends an abstract
type, or it is not an extension of another type.

4) A method MAY BE declared ABSTRACT providing that (i) it is bound to an
abstract type, and (ii) it does not redefine a concrete method. That is,
abstract methods must be newly introduced methods, or redefinitions of
existing abstract methods.

5) An abstract type MUST BE declared with the ABSTRACT tag. A concrete type
must implement all abstract methods defined in its base type. The compiler
will report an error if a concrete type has unimplemented abstract methods.

6) An abstract method MAY NOT be called via a super call. Note that given
the static type of a pointer, it is possible to determine at compile time
if a method is abstract or concrete within the super-class. Super calls to
abstract methods will cause the compiler to generate an error.

7) An exported abstract type MUST export all abstract methods. Otherwise,
non-exported abstract methods can never be redefined as concrete methods,
and the type can never have a concrete extension. Note that Component
Pascal suffers from this problem.

Questions:

Q1: Logically, an abstract method may redefine another abstract method. In
practice, when would this be used?

Q2: How do we enable abstract types in the module header? More generally,
how do we enable optional features in the compiler?

One way might be to have a kind of meta-import statement which specifies
which system flags are to be enabled. For example,

MODULE Channel [IMPORT ABSTRACT];

or

MODULE WinApi [
  IMPORT CSTRING, ALIGN1, ALIGN2, ALIGN4, UNION, UNTAGGED, NIL_COMPAT;
  INTERFACE "Pascal"; 
  LINK
    LIB "kernel32";
    LIB "user32";
    LIB "gdi32"
  END
];

Although its more complex, it might be nice to be able to group related
flags together (eg. the alignment tags could be imported as ALIGNMENT).

- Stewart