From JLS@liverpool.ac.uk Fri Oct 16 18:30:47 1992
Received: from vm.uni-c.dk by dkuug.dk with SMTP id AA07208
  (5.65c8/IDA-1.4.4j for <SC22WG5@DKUUG.DK>); Fri, 16 Oct 1992 17:24:49 +0100
Received: from vm.uni-c.dk by vm.uni-c.dk (IBM VM SMTP V2R2) with BSMTP id 3452;
   Fri, 16 Oct 92 17:16:38 DNT
Received: from UKACRL.BITNET by vm.uni-c.dk (Mailer R2.07) with BSMTP id 7421;
 Fri, 16 Oct 92 17:16:37 DNT
Received: from RL.IB by UKACRL.BITNET (Mailer R2.07) with BSMTP id 1767; Fri,
 16 Oct 92 17:16:38 BST
Received: from RL.IB by UK.AC.RL.IB (Mailer R2.07) with BSMTP id 9760; Fri, 16
 Oct 92 17:16:35 BST
Via:        UK.AC.LIV.LIVBIRD; 16 OCT 92 17:16:27 BST
Received: from ibm.liverpool.ac.uk by liverbird.liverpool.ac.uk via JANET
          with NIFTP (PP) id <21235-0@liverbird.liverpool.ac.uk>;
          Fri, 16 Oct 1992 17:09:42 +0100
Received:   from UK.AC.LIVERPOOL by MAILER(4.4.t); 16 Oct 1992 17:08:17 BST
Date:       Fri, 16 Oct 92 16:45:20 BST
From: Lawrie Schonfelder <JLS@liverpool.ac.uk>
Subject:    Some thoughts on OOP
To: SC22/WG5 members <SC22WG5@dkuug.dk>
Message-Id: <"liverbird..237:16.09.92.16.09.46"@liverbird.liverpool.ac.uk>
X-Charset: ASCII
X-Char-Esc: 38

I amused myself on a long train journey the other day by writing down some
thoughts about F90 (F9x/F2000) and OOP. Here is the result for good or ill.








                                           WG5(92/93) JLS-1
TO:    ISI/IEC JTC1/SC22/WG5
FROM:  Lawrie Schonfelder
SUBJECT:   FORTRAN 90 IS ALREADY OBJECT ORIENTED (Well almost)

Fortran 90 has already much of the technology needed to provide for
"Object Oriented Programming".  If a good deal of the fashionable hype and
the evangelical dogma is ignored, then the data-abstraction facilities of
Fortran 90 provide a very good basis on which to build OOP functionality.

The analogue of the class concept of C++, or object oriented Pascal is a
Module with certain properties.  Such a module will contain the definition
of a new type.  It will also contain a set of procedures (Generic most likely)
and operators that operate on "objects" of this type.  These are essentially
class methods.  The VARYING-STRING module is a paradigm example.
The inheritance property of OOP is provided by the fact that a new "class"
module can USE an existing "class" module.  The new module can create its
new type with fields of the USEd type.  These fields have the properties of
the old type and can be manipulated by all the "methods" of the old type.
They inherit the characteristics of the parent class.

The Module provides encapsulation and inheritance.  The generic procedure
facilities provide the related methods, and the PUBLIC/PRIVATE
capability provide the controls on visibility.

That there are deficiencies in the F90 capability in this area is, however, also
apparent.  Fortran 90 is still essentially built with an underlying model of a
single thread of execution.  This is not explicit and processors could fork the
execution of suitable Fortran 90 programs into multiple parallel executing
threads but this is essentially invisible to the user.  In general, I think this
to
be highly desirable.  As scientific/engineering application language F90
should be largely designed to allow the efficient specification of the problem
to be solved not the details of how this is to be mapped onto any particular
machine architecture.  However, in a true object oriented world the
application domain would necessarily include multiple objects all
simultaneously interacting.  A programming representation of such a world
would presumably require explicit manipulation of multiple treads of
execution.  Adding this capability would be a very big extension to Fortran.

The construction/destruction of objects is another area where F90 is
currently deficient; it is deficient in this area in the more restricted
functionality for data-abstraction.  F90 creates objects by declaration, or
allocation, and these become fully instantiated (defined) by initialisation,
assignment or by being given a value as a result of input.  Of these processes
only assignment is properly extended.

Although a default "constructor" is created implicitly by the type definition,
this is rendered invisible by making the structure of the type PRIVATE.
Nor is it possible for the user to define an additional constructor either to
overload the default or to override it.  It is not possible either for user
supplied procedures to appear in initialization expressions.  These are all
fairly trivial restrictions which would not require major syntactic changes to
rectify.  These defects do however have a significant effect in damaging the
functionality of the language both in its capability for sematic extension by
data-abstraction and in providing a base for OOP.

More difficult to fix would be the issue of initial state for objects created by
allocation.  Here it is not a matter of relaxing unnecessary restrictions on a
more or less adequate syntax.  There is no existing syntax.

F90 essentially treats object creation as a three step process.  Create the
name to be used for referencing the object, create the space to hold the
object followed by a separate action for defining the values to be stored in
that space. Declaration normally performs the the first two operations,
except when the declaration is explicitly made to do only the first; when
either the POINTER or ALLOCATABLE attribute are specified. For
normal declarations the third operation can also be indicated by the
specification of an initial value. Allocation only does only the middle part
of creating the space.  It would appear that we need some way of indicating
that for certain objects the space creation operation should be accompanied by
a definition of its values or state.  That is, we should be able to define a
constructor that is applied to initialise such objects even if they are created
by allocation.

The object destruction situation is also somewhat deficient. Deallocation
"destroys" the space occupied by certain objects and hence also the values.
Some objects are automatically destroyed when the procedures in which they
are declared complete, but the destruction processes are not in any way
subject to user definition.  The process is entirely processor determined.
However, a user supplied procedure could always be called prior to any
deallocate or destructive return, but this does not seem to be a satifactory
solution to the problem.

A more serious inconvenience, and potential inefficiency is in the lack of
type modelling (sub-typing) and associated operation/method inheritance
control.  This is best illustrated by a concrete example.  The example I shall
use is drawn from classical undergraduate mechanics, in one dimension
(Fortran is, after all, essentially a language for expressing scientific
problems
not for writing operating systems so this is perhaps a reasonable example).
The quantities that are relevant to such a modelling activity are mass, time,
displacement, velocity, acceleration, force, etc.  These are all modelled in a
1D world by real numbers, but the semantics of the physics involved places
constraints on the values that can be taken by the various quantities and on
the operations of real arithmetic that make sense.  For example, mass
cannot be zero or negative.  Times might be added to times, but there is no
valid mechanical operation where a time is added to a force, say.  In spite
of the fact that all these quantities are modelled by real numbers, the
operations of real arithmetic are not sensibly inherited to apply to all
quantities. This situation can, in fact, be handled by F90 as it stands, but not
very conveniently.

It would be possible to define each of these quantities as a type such as:
TYPE MASS
  PRIVATE
  REAL:: m
END TYPE
TYPE TIME
  PRIVATE
  REAL:: t
ENDTYPE             etc.

and then all the allowable operation combinations could be defined by
generic (operator) functions.

This would be impossibly tedious as most of them would require things like
...
INTERFACE OPERATOR(*)
   MODULE PROCEDURE add_mass_mass, add_time_time
END INTERFACE
CONTAINS
FUNCTION add_mass_mass (mr, ml)
TYPE(MASS):: mr, ml, add_mass_mass
  add_mass_mass = mr + ml
END FUNCTION
...
     add nauseam.

It would be much easier if we could indicate explicitly that such objects were
to be represented by subtypes of an existing type, but that only a restricted
set of the operations of the underlying type should be inherited; so that the
restrictions of the semantic model can be easily expressed. Such expression
should give rise to implemetations that are more easily efficient than the
current syntax.

OUTLINE PROPOSALS TO FIX SOME OF THESE PROBLEMS

1. Allow User Defined Constructors

This is the easiest of the deficiencies to fix. It requires no additional
syntax.
All that is required is that the implicitly defined constructor for a derived
type be recognised for what it is, namely an implicitly defined generic
intrinsic type conversion function. The constructor for a derived type is an
analog of the function REAL() for the REAL type. Such a classification
allows the user to overload the constructor name by defining further specific
procedures that are added to the generic set. The only restriction is that any
user defined procedure with the same generic name must have arguments
which are sufficiently different from those of the implicit constructor to
make the whole overload set unambiguous. Even this restriction would not
be necessary. The overloading of constructors could be treated in the same
manner as assignment. In this case if a user defined assignment is ambiguous
with the default intrinsic assignment the user definition is used. The intrinsic
assignment is overidden and it would be quite consistent to allow intrinsic
constructor to be overidden similarly.

2. Allow User Defined Procedures in initialisation expressions.

The restrictions applied to initialisation expressions are too tight. They are
currently constrained so that their value can be determined statically at
compile time. This restriction is not necessary or not necessary except in a
much smaller subset of cases than currently. The restrictions to allow static
evaluation are required for KIND value expressions, but there is no major
reason for requiring static evaluation for variable initialisation. All that is
essential is that the evaluation can be performed when the object is created.
At this time any user defined constructor function must be accessible.

3. Allow for Multi-threaded Event Driven Programs

I have no detailed idea of how best to achieve this but I believe this to
be critical both for OOP and for the long term use of high performance
systems.
