From jls@liverpool.ac.uk Thu Dec 23 11:24:23 1993
Received: from ns.dknet.dk by dkuug.dk with SMTP id AA25423
  (5.65c8/IDA-1.4.4j for <SC22WG5@dkuug.dk>); Thu, 23 Dec 1993 13:38:02 +0100
Received: from mail.liv.ac.uk by ns.dknet.dk with SMTP id AA18582
  (5.65c8/IDA-1.4.4j for <SC22WG5@dkuug.dk>); Thu, 23 Dec 1993 12:39:58 +0100
Received: from liverpool.ac.uk by mailhub.liverpool.ac.uk with SMTP (PP) 
          id <08258-0@mailhub.liverpool.ac.uk>; Thu, 23 Dec 1993 11:24:33 +0000
From: "Dr.J.L.Schonfelder" <jls@liverpool.ac.uk>
Message-Id: <9312231124.AA20824@uxe.liv.ac.uk>
Subject: Parameterised Datatypes
To: SC22WG5@dkuug.dk (SC22/WG5 members)
Date: Thu, 23 Dec 1993 11:24:23 +0000 (GMT)
X-Mailer: ELM [version 2.4 PL23]
Mime-Version: 1.0
Content-Type: text/plain; charset=US-ASCII
Content-Transfer-Encoding: 7bit
Content-Length: 23554
X-Charset: ASCII
X-Char-Esc: 29

David M. Please add this to the pre meeting.

I have revised the proposal in the light of comments from J3 and after discussion
in the UK panel. The UK panel will be looking at polishing the editorial
quality further before the J3 meeting in Feb. and as the principal author
I would welcome comments.
--------------------------------------------------------------------------
To: X3J3 and WG5 (22 December 1993)
From: Lawrie Schonfelder (on behalf of the UK panel IST/5/-/5)
 
                         Parameterised Derived Types

1 Introduction  
This paper is an update of the paper on the same topic presented to
the above committees in early November '93. It has been modified to
incorporate some of the technical improvements suggested at meeting
127 of X3J3 and it includes additional explanatory material to
clarify some of the issues raised inconclusively at the same meeting.
In the light of the views expressed by X3J3 the two reduced proposals
of the previous paper have not been considered further; only the full
functionality proposal has been developed. Much of the rationale and
background material has been retained.
    There is substantial need for the regularisation of Fortran to
allow all types both intrinsic and derived to be parameterised.  The
lack of parameterised derived types greatly restricts their use in
contexts where they are required to interwork with parameterised
intrinsic types.  As a result of this WG5 requested that proposals
to include this functionality be considered for the 95 revision of
the language. X3J3 asked the UK, in particular JLS, to prepare an
initial paper describing possible approaches to the issue.  This
paper is a revision of the original proposals prepared to meet that
brief. 

2 An informal outline of the proposal   
The intrinsic types have two quite different parameters.  There are
the static parameters that determine the nature of the machine
representation. These are all characterised for the intrinsic types
by the same keyword, KIND, being used for such a parameter.  The
other parameter type where the value is not necessarily static, only
applies for the character type.  Here the parameter, LEN, determines
the length or the number of characters in the datum.  A full
parameterised data type proposal must allow for any number of both
sorts of parameter for user defined types.
    The general approach to the problem is to allow the user to
specify a set of dummy parameters as part of a derived type
definition. These parameters are then used within the definition as
primaries in specification expressions determining array bounds and
character lengths, etc., for components.  Actual values must be
supplied when objects of the type are declared or constructed.  For
example, we might define a type MATRIX with a parameter to determine
its dimensionality,

TYPE MATRIX(dim)
  REAL,DIMENSION(dim,dim) :: element
ENDTYPE MATRIX

objects of this type could then be declared,

type(MATRIX(3)) :: rotate,trans
type(MATRIX(4)) :: metric
type(MATRIX(dim=n)) :: weight
type(MATRIX(dim=*)) :: hessian

where the penultimate statement would be declaring an automatic or
dummy object and the ultimate would be declaring a dummy argument
that was to assume the parameter value from the associated actual
argument, c.f. similar usage with the length parameter for
characters. Note that, by definition the parameters are of type
integer. 
    The handling from a descriptional point of view such LEN-style
parameters is quite straight forward. Much of the necessary text
already exists in IS 1539 : 1991 as it applies to the character
length parameter; in particular the actual values for such parameters
are provided by specification expressions or are assumed. 
    There are more significant complications when KIND-style
parameters are required.  Basically, if a parameter is used within
a type definition to determine the kind of a component type then as
for intrinsic types the actual values of such parameters must be
static and hence restricted to being determined by initialisation
expressions.  If in the above example we wanted to have a general
matrix type which had user selected component kind as well as user
specified dimensionality we might wish to have a type simplistically
expressed as,

TYPE MATRIX(com_kind,dim)
  REAL(com_kind),DIMENSION(dim,dim) :: element
ENDTYPE MATRIX

and declarations of the form,

type(MATRIX(4,3)) :: rotate,trans
type(MATRIX(8,4)) :: metric
type(MATRIX(com_kind=4,dim=n)) :: weight

where now although the dim parameter may be given by a specification
expression or *, the com_kind parameter must be an initialisation
expression. As with character a difference in kind style values would
be able to resolve overloads but those of length style ones would
not.    Semantically the distinction between which parameters are
kind-style and which are not is easy.  Any parameter which ultimately
is used to determine the kind of a component must be a kind-style
parameter. This semantic difference could be detected and enforced
by the compiler but if no syntactic differentiation is provided it
could be very difficult for the user to see the very significantly
different semantic restrictions that apply. In general where some
semantic restriction applies to the use of an entity in Fortran, the
language provides some syntactic mechanism to specify that any
particular entity possesses an attribute which controls the nature
of the entities use, c.f. INTENT and PRIVATE attributes. 
    The question is how should the kind/nonkind distinction be
indicated syntactically so that the nature of a given parameter is
always clear at compile time.  For the intrinsic types this has been
done by always using the keyword KIND for such parameters.  However,
this approach does not readily generalise to derived types which may
have arbitrarily complex component structures and may need to have
multiple kind-style parameters for a single type. The syntactic
device suggested at X3J3 meeting 127 for handling this is to require
all kind-style parameters to be declared as such in the type-
definition. 
    The  proposed syntax would require the above matrix type to be
defined,

TYPE MATRIX(KIND::com_kind,dim)
  REAL(com_kind),DIMENSION(dim,dim) :: element
ENDTYPE MATRIX

where the KIND:: specifies that the name com_kind is to be used for
a kind-style parameter.
    This syntax would allow a type such as

TYPE WEIRD(kind::c,kind::r,kind::i,maxlen)
  CHARACTER(KIND=c,LEN=maxlen) :: desc
  REAL(KIND=r) :: x,y,z
  INTEGER(KIND=i) :: id
ENDTYPE WEIRD

to be written.  The declaration of an object of this type would then
look like,

type(WEIRD(c=1,r=8,i=2,maxlen=20)) :: funset(100)

This would create an array of 100 objects of type WEIRD each of which
had a character component of length 20 and kind 1, three real
components each of kind 8, and an integer component of kind 2. 
    Another possibility would be to include the kind declaration
within the body of the type definition, e.g.

TYPE MATRIX(com_kind,dim)
  KIND :: com_kind
  REAL(com_kind),DIMENSION(dim,dim) :: element
ENDTYPE MATRIX

where the KIND attribute specifies that the name com_kind which is
that of a dummy type parameter, is to be used for a kind-style
parameter. This syntax would require

TYPE WEIRD(c,r,i,maxlen)
  KIND :: c,r,i
  CHARACTER(KIND=c,LEN=maxlen) :: desc
  REAL(KIND=r) :: x,y,z
  INTEGER(KIND=i) :: id
ENDTYPE WEIRD

as the type definition for the WEIRD type.  The declaration of an
object of this type would be as before. 
    As a general rule where we have choice attributes like PRIVATE,
or INTENT, we have attribute keywords for all options so as to allow
positive specification rather than simply relying on a default for
one of the choices. To this end we need two attributes KIND and
NONKIND.  The full definition of the above type would therefore
become:

TYPE WEIRD(c,r,i,maxlen)
  KIND :: c,r,i
  NONKIND :: maxlen
  CHARACTER(KIND=c,LEN=maxlen) :: desc
  REAL(KIND=r) :: x,y,z
  INTEGER(KIND=i) :: id
ENDTYPE WEIRD

The declaration of the attributes of the dummy type parameters within
the body of the definition is much more consistent with the normal
syntactic style of Fortran than including this particular attribute
specification in-line with the parameter name list on the type
definition statement. Type definitions are very similar to compile
time subroutines and much of the normal syntax of subroutine argument
lists can and should be applied. In what follows this is the approach
that will be developed.
    Note, that by definition all type parameters are of integer type
so this does not have to be declared. It would be perfectly possible
to allow such declaration but this is not included in this proposal.
However, the use of such declarations in the future is not ruled out
by this proposal, nor is the possibility of parameters of types other
than integer constrained.  
    A further major semantic distinction between kind-style and non
kind-style parameters is in their use with procedure arguments. 
Again as with intrinsic types, kind parameter values for arguments
may resolve overloads but non-kind parameter values cannot since they
are not necessarily static.  Non-kind parameter values for dummy
arguments may be assumed and hence specified by an asterisk. Kind
parameter values cannot be assumed and hence must always be
explicitly specified even for dummy arguments. Again this follows
precisely the rules that apply for the corresponding intrinsic
parameters. 
    As for the intrinsic types each parameter must have associated
with it an inquiry function with a generic name that is that of the
parameter.  Such functions would take as their single argument any
object of the type having the parameter and would return the current
value for that parameter.  The defining of a parameterised type
creates implicitly an inquiry function for every parameter.  Thus for
the types defined above there would be functions for each of the
parameters defined and the following calls would yield the indicated
results.

com_kind(metric) = 8
dim(metric) = 4
i(funset(1)) = 2
maxlen(funset) = 20

Where these functions relate to kind parameters they would need to
be allowed in initialisation expressions. Where they applied to
nonkind parameters they would need to be allowed in specification
expressions. Their primary use, as with KIND() and LEN() will be for
the declaration of local objects which have the same type and type
parameters as for other objects; frequently these other objects will
be dummy arguments with assumed values for their parameters.
    Such inquiry functions are essential for regularity with the
intrinsic types. In many cases there will be no other way of
obtaining the relevant information provided by such functions. Where
the internal component structure of the type is fully accessible it
would in principle be possible for the programmer to "unwrap" the
structure and use existing intrinsic inquiry functions on the
ultimate components and then by inverting the expression chain
reconstruct the original parameter values. In simple cases this might
be relatively straight forward, but in general this could be a very
involved process. More critically, where the internal structure of
the type is PRIVATE this is not possible even in principle. For
example, suppose we had a derived type for a variance-covariance
matrix. 

TYPE VAR_COV(DIM)
  NONKIND :: DIM
  PRIVATE
  REAL,DIMENSION(1:DIM,1:DIM) :: cor
ENDTYPE VAR_COV

might well be a suitable representation, but since variance-
covariance matrices are by definition symmetric we might prefer to
store only the lower triangle of different elements. The
dimensionality remains the same but the relationship between the
actual parameter and the internal components is very different,

TYPE VAR_COV(DIM)
  NONKIND :: DIM
  PRIVATE
  REAL,DIMENSION(1:DIM*(DIM+1)/2) :: cor
ENDTYPE VAR_COV

Without an inquiry function to access the value of DIM for an object
of such a type there is no way a USEing program can properly handle
automatic or assumed DIM values for such objects; forcing the passing
of explicit arguments to carry the DIM values is not an acceptable
alternative. Such inquiry functions do add names to the name-space
but only as generic names restricted in scope to the  program units
in which the type is accessible.
    A further extension is in the syntax of the value constructor. 
One approach that could be used would be to extend the analogy with
the REAL type conversion function and the type value constructor
which also behaves syntactically like a function reference and acts
essentially as a type converter.  In this case the extended form of
the constructor reference would be to include the parameters as an
extra set of arguments following the list of component expressions. 
The analogy with

REAL(A,KIND)

for  the matrix type would be

MATRIX(element,com_kind,dim)

Another approach would be simply to extend the constructor syntax
with the type-name now having if necessary an attached list of
parameters,

MATRIX(com_kind,dim)(element)

The semantics in each case would be the same.  The element would have
to be a rank 2 array of reals with dimensions that matched those
specified by dim.  The assignment coercion would apply so as to
ensure that regardless of the kind of the array the kind of the value
produced would be as specified by the parameter.  
(My preference would be to adopt the former approach as this is more
regular and more extensible; it does not require a new and rather odd
syntactic entity of  concatenated parenthetical lists. In meeting 127
X3J3 expressed a preference for the second form; reversing the view
it took on the same alternatives when these were discussed for the
type conversion intrinsic functions. Plus _a change.... )

    Finally intrinsic assignment is defined only when the variable
and expression have the same type, type parameter values, and rank.
There is no attempt to define default coercions between differing
type parameter values. If the user requires such assignments they
must provide an assignment procedure to extend and override this
default.


3 Edits to IS 1539 : 1991   
The following are a first attempt at providing edits to the current
document to implement the above functionality. 
    Note, where new syntax rules are inserted they are numbered with
a decimal addition to the rule number that precedes them. In the
actual document these will have to be properly numbered in the
revised sequence.

3.1 2.4.1.2 [13/22]
    before "agreement" add "and type parameter"

3.2 4   [25/14]
    replace "Intrinsic data-types are" by "Data types may be"

3.3 4.4.1   [32/41]
    Add line following 
                    [param-spec-stmt]...

3.4 4.4.1   [33/3]
    Add to end of R424 "[(dummy-type-param-list)]"

    Add new rule
R424.1  dummy-type-param     is     type-param-name

    Add constraint
Constraint: If the derived-type-stmt specifies type parameters,
            SEQUENCE must not be present.

3.5 4.4.1   [33/16]
    Add following
R425.1  param-spec-stmt is  KIND [::] dummy-type-param-list
                        or  NONKIND [::] dummy-type-param-list

If a dummy type parameter is specified in a param-spec-stmt with a
KIND attribute, such a parameter is a kind type parameter. All other
dummy type parameters, whether specified with a NONKIND attribute or
not are nonkind type parameters, and these must not be used to
determine the  values of actual kind type parameters of components.

3.6 4.4.1   [33/26]
    Add constraints
Constraint: If the type-spec specifies a value for a kind type
            parameter, this must be a scalar integer
            initialisation expression, or a scalar initialisation
            expression  involving as primaries the names of one
            or more dummy kind type parameters specified on the
            derived-type-stmt.
Constraint: If the type-spec specifies a value for a nonkind type
            parameter, this must be a scalar integer constant
            expression, or a scalar integer constant expression
            involving as primaries dummy type parameter names
            specified on the derived-type-stmt.

3.7 4.4.1   [33/37]
    Add at end of line "or a constant expression involving as
primaries dummy type parameter names specified on the derived-type-
stmt."

3.8 4.4.1   [33/38]
    Add following paragraph
If the type is defined with type parameters actual values for these
must be specified when an entity of this type is declared or
constructed. These values may be used via the associated dummy type
parameter names to specify character lengths, array bounds, kinds or
other type parameter values for components of the type.

3.9 4.4.1   [34/34]
    Add following paragraph
Examples of type-definitions with type parameters are:

TYPE VECTOR(WP, ORDER)
  KIND :: WP
  NONKIND :: ORDER
  REAL(KIND=WP) :: comp(1:ORDER)
ENDTYPE VECTOR

Objects of type VECTOR could be declared:

TYPE(VECTOR(4,3)) :: rotation
TYPE(VECTOR(8,100)) :: steepest

The scalar variable rotation is a three-vector with each component
represented by a kind=4 real. The scalar vector steepest is vector
in a 100 dimension space and each component is represented by a
kind=8 real.

For each type parameter specified there is a generic inquiry function
that is created and defined implicitly by the type definition. This
function has the type parameter name as its generic name, it takes
as its argument any entity of the derived type, and it returns as its
result the integer value for this parameter that applies for its
argument, for example, WP(rotation) would return 4 and
ORDER(steepest)would return 100. These type parameter inquiry
functions are accessible if and only if the derived type is
accessible.

3.10 4.4.4  [37/3]
    Replace "value of" by "value of the"

3.11 4.4.4  [37/5]
    Replace "expr-list" by "expr-list[,type-param-expr-list]"
    Add constraint
Constraint: If the derived type definition referenced by type-
            name specifies one or more type parameters, the type-
            param-expr-list must be present and not otherwise.

3.12 4.4.4  [37/10]
    Before "A structure" add
The type parameter expressions, if present, provide values for the
type parameters specified for the type and hence control the possible
kinds, lengths, shapes and type parameters of the components.

3.13 4.4.4  [37/16]
    Add the following paragraph
An example of a constructor for a parameterised type is:

VECTOR(0.0,8,3)

This would construct a three-vector whose components were all zero
and of kind=8 real.

3.14 5.1    [39/24]
    Replace "type-name" by "type-name[type-selector]"

3.15 5.1    [39/39]
    Add constraint
Constraint: The type-selector must appear if the type is
            parameterised and must not appear otherwise.

3.16 5.1.1.7    [43/23]
    Add rules and constraints
R509.1  type-selector   is  (type-param-selector-list)

R509.2  type-param-selector     is  [type-param-name=]type-param-
expr

R509.3  type-param-expr  is     scalar-int-initialisation-expr
                     or     type-param-value

Constraint: There must be one and only one type-param-selector
            corresponding to each type parameter specified for
            the type in its type definition.

Constraint: The type-param-expr must be a scalar-int-
            initialisation-expr if the corresponding type
            parameter is a kind type parameter.

Constraint: The type-param-name= may be omitted from the list if
            it was omitted from all previous type-param-selector
            in the list.

The type selector, if present, specifies the values to be used for
the type parameters of the type and hence the values to be used to
determine the specified properties of the dependent components of the
type.

{{{{Note for the editor: The rules associated with type-param-values,
in particular automatic and assumed type parameters, appear to be
covered in the description for character length. A reordering of this
material might read better but I think the current text is actually
correct even though it now has extended effect. It is probably now
in the wrong place in the chapter.}}}}

3.17 7.1.4.2    [76/24]
    After the second "The type" add "and type parameters."

3.18 7.1.4.2    [76/48]
    Add
"The type parameters of a derived type expression, if any, are
determined by the function defining the operation."

3.19 7.1.6.1    [78/7]
    After "KIND" add
    ", a derived-type kind type parameter inquiry function"

3.20 7.1.6.2    [79/12] 
    After "KIND" add
    ", a derived-type type parameter inquiry function"

3.21 7.1.7      [80/29]
    Add paragraph
The appearance of a structure constructor requires the evaluation of
the component expressions and may require the evaluation of type
parameter expressions. The type of an expression in which a structure
constructor appears does not affect, and is not effected by, the
evaluation of such expressions, except that evaluation of the kind
type parameters may affect the resolution of a generic reference to
a defined operation or function and hence may affect the expression
type.

3.22 7.5.1.2    [89/28]
    Replace "type," by "type and the same type parameter values,"

3.23 7.5.1.2    [89/41]
    Replace "type as" by "type and the same type parameter values as"

3.24 12.2.1.1   [166/6]
    Replace "or character length" by " character length, or nonkind
type parameter"

3.25 12.3.1.1   [167/2]
    Replace "that" by "that assumes the value for a nonkind derived
type parameter or that"
 
3.26 12.3.1.1   [167/4]
    Add additional item to list and renumber list
    (e) A result with a nonconstant type parameter value (derived
        type functions only)

3.27 12.4.1.1   [172/41]
    Add sentence
The nonkind type parameters of the actual argument must agree with
those of the dummy argument.

3.28 13.5       [184/27+]
{{{{Editor note, since I am no longer proposing that the inquiry
functions be classified as intrinsic this text is probably not
appropriate in this location. However, I think it probably needs to
be said and I a not sure where it would best be placed.}}}}
    Add new section 13.5.6 and renumber subsequent sections as
required
13.5.6  Derived Type Inquiry functions
For each type parameter specified in a derived type definition
(4.4.1) there is an inquiry function of the parameter name taking an
object of the relevant type as its argument that returns the value
of the named parameter. The value of the argument need not be
defined. It is not necessary for the processor to evaluate the
argument of this function if the value of the function can be
determined otherwise.
For example, given a type defined as

TYPE MATRIX(KIND::WP,ORDER)
  REAL(KIND=WP),DIMENSION(ORDER,ORDER)
ENDTYPE MATRIX

and the object declaration

TYPE(MATRIX(WP=4,ORDER=9)) :: weight

the derived type inquiry function

ORDER(weight)

would return the integer value 9.

3.29 14.1.2 [241/26]
    Replace ", in" by " and type parameters, in"

3.30 11.3.2 [158/16]
    Add sentence
If a derived type type parameter name is renamed, the local name is
used for both the type parameter inquiry function and the type
parameter keyword name used when specifying actual type parameter
values.

4 Proposal  
That facilities for parameterising derived types as set out above be
added to Fortran at the 1995 revision.

-- 
Dr.J.L.Schonfelder
Director, Computing Services Dept.
University of Liverpool, UK
Phone: +44(51)794 3716
FAX  : +44(51)794 3759
email: jls@liv.ac.uk   

