X3J3 / 96-141R1
Date: Aug 14, 1996
To: X3J3
From: Data
Subject: Specs for R.5, PDTs
This paper summarizes the specifications for parameterized
derived types, item R.5 on the F2k requirements list of
X3J3/96-115r4. These specifications are based on those in the
WG5 D28 paper labelled "Option 2 + Component Selection", which
appears as part of X3J3/96-125 as a starting point. The current
paper summarizes those specifications and makes some further
refinements and modifications. The rationale and discussions are
mostly omitted from this summary in order to keep it short; they
are well presented in paper D28.
1. Type-definition statement
An optional list of type parameter names may be added in parens
following the type-name in a type-definition statement.
Example:
type matrix(kind, dim)
2. Type parameter typing
All type parameters are of type integer. This may be confirmed
by an explicit INTEGER declaration in the derived type
definition. An explicit declaration can also be used to
declare a type parameter to be of an integer kind other than
default integer.
Examples:
type matrix(kind, dim)
!-- kind and dim are implicitly default integer
real(kind) :: element(dim, dim)
end type
type humogous_matrix(kind, dim)
integer :: kind !-- Confirms kind as default integer
integer(selected_int_kind(12)) :: dim
!-- Specify a non-default kind for dim
real(kind) :: element(dim, dim)
end type
3. Kind vs non-kind parameters
Type parameters are either kind type parameters on non-kind
type parameters. Kind type parameters participate in overload
resolution and may appear in initialization expressions
(particularly, in kind expressions for components) and in
specification expressions. Non-kind type parameters do not
participate in overload resolution and may not appear in
initialization expressions; they may appear in specification
expressions. A kind type parameter is said to have the KIND
attribute.
A type parameter may be declared to have the KIND attribute by
using a KIND attribute on the INTEGER declaration of the
parameter. It may also be declared to not have the KIND
attribute by using a NO_KIND attribute. If a type parameter
does not explicitly or implicitly (see below) have the KIND
attribute, then it has the NO_KIND attribute by default;
it is never required to explicitly specify the NO_KIND
attribute, but it is allowed as a confirmation.
Example:
type stuff(kind, dim)
integer, kind :: kind
integer, no_kind :: dim
real(kind) :: element(dim, dim)
real(kind+1) :: scratch(2*dim)
!-- kind is used as a primary in initialization exprs.
!-- dim is used as a primary in specification exprs.
end type
4. Implicit kind declaration
With the exception mentioned below, appearance of a type
parameter in an initialization expression implicitly declares
it to have the kind attribute. This implicit declaration may
be confirmed by an explicit declaration. It is an error for a
type parameter to appear in an initialization expression if the
type parameter was declared with the NO_KIND attribute.
Example:
type matrix(kind, dim)
real(kind) :: element(dim, dim)
end type
!-- kind is implicitly a kind type parameter because
!-- it appears in an initialization expr.
!-- dim is implicitly no_kind.
If a derived type MY_TYPE has a component COMP that is a
pointer to a (possibly different) derived type, the appearance
of a type parameter of MY_TYPE in the expressions for the kind
type parameter values of COMP implicitly declares it to be a
kind type parameter of MY_TYPE only if the type definition for
COMP precedes that of MY_TYPE. For example
type type_1(a)
integer, kind :: a !-- required because we don't yet know
!-- whether type_2 has a kind type parameter.
type(type_2(a)), pointer :: comp
end type
type type_2(b)
!-- No explicit declaration of b needed here.
type(type_1(b)), pointer :: comp
end type
Note that this is never at issue except with pointer
components.
5. Object declaration.
The syntax for declaring an object of parameterized derived
type closely follows that of intrinsic parameterized types.
The type parameter values are specified in parens after the
type name, in either keyword or positional form. There are no
optional type parameters for derived types, so there is no
concept of a default type-parameter value.
The expression for a kind type parameter shall be an integer
initialization expression. The expression for a non-kind type
parameter may be either a specification expression or assumed.
The expressions for type parameter values need not be of the
same integer kind as the type parameter.
Examples:
type(matrix(4,1000)) :: a
type(matrix(kind=4,dim=1000) :: b
subroutine sub(c, d, n)
integer :: n
type(matrix(kind=8, dim=*)) :: c
type(matrix(kind=8, dim=2*n)) :: d
6. Constructors
Steve's paper proposed to redefine all derived type
constructors (not just those for parameterized derived types)
to be generic functions. This raises several subtle points
that are largely orthogonal to the introduction of
parameterized derived types. Those points do not appear to be
addressed in Steve's proposal.
Therefore, data proposes to separate these issues. A
subsequent proposal might make this modification, but for now
this proposal is less ambitious.
A constructor for a parameterized derived type has the same
form as the constructor for the existing derived types, with
the addition of the type parameters at the end of the list.
The form of all derived type constructors is also enhanced to
allow a keyword form syntactically identical to that of a
function call. However, we avoid for now the extra
complications of actually defining these constructors to be
functions.
Examples:
type stock_item !-- Note this is *not* a pdt.
integer :: id, holding, buy_level
character(len=20) :: desc
real :: buy_price, sell_price
end type
type(stock_item) :: &
s = stock_item(12345,75,10,"pencils", 1.5, 2.4)
...
s = stock_item(desc="pencils", id=12345, &
holding=75, sell_price=2.4, &
buy_level=10, buy_price=1.5)
type node(key_len) !-- This one is a pdt
character(key_len) :: desc
type(node(keylen)), pointer :: next
end type
type (node(16)) :: word
...
word = node("ralph", null(), key_len=16)
7. Type parameter inquiry
Component selection syntax is used to inquire about type
parameter values. An inquiry about a kind type parameter can
appear as a primary in an initialization expression; an inquiry
about a non-kind type parameter can appear as a primary in an
initialization expression if the actual value inquired about
was defined as a constant expression. an inquiry about any
type parameter can appear as a primary in a specification
expression.
This directly follows the existing rules for how the existing
intrinsic inquiry functions can be used.
Examples:
word%key_len !-- word declared as above.
The component selection syntax is also extended to the
intrinsic types.
Examples:
real(4) :: a
character*20 :: c
write (*,*) a%kind, c%len !-- i.e. 4 and 20
8. Intrinsic assignment
Intrinsic assigment for parameterized derived types is defined
only when the variable and expression have the same type and type
parameter values
9. Argument association and overload rules
The argument association rules follow those for objects of
intrinsic types. The actual and dummy arguments must agree in
type and type parameters. For non-kind parameters, the dummy
argument may assume the value from the actual argument.
Kind-type parameters may not be assumed. Kind type parameters
may be used to resolve generic overloads.
Examples:
type(matrix(kind=4, dim=100)) :: a
call sub(a)
...
subroutine sub(b)
type(matrix(kind=4, dim=*)) :: b !-- dim is assumed.
module matrix_manipulation
type matrix(kind, dim)
real(kind) :: element(dim, dim)
end type
interface invert_in_place
module procedure invert_single, invert_double
end interface
contains
subroutine invert_single(a)
type(matrix(kind=4, dim=*)), intent(inout) :: a
...
end subroutine invert_single
subroutine invert_double(a)
type(matrix(kind=8, dim=*)), intent(inout) :: a
...
end subroutine invert_double
end module matrix_manipulation
10. Visibility and scoping
The type parameter names are useable as keywords in object
declarations even when the derived type has private components.
Likewise, the parameter values can be inquired about even when
the components of the derived type are private.
Thus the type parameter names have more visibility than the
component names. This is consistent with the usage with
intrinsic types. This is not the rule proposed in Steve's
paper.
Also Steve's paper mentioned renames for type parameters.
No such facility exists or is proposed; this mention was
presumably a holdover from the inquiry function approach.
11. Sequence
Parameterized derived types may have the SEQUENCE property.
A parameterized derived type is never considered a numeric
or character sequence type even if all of its ultimate
components are numeric or character.
Sequence parameterized derived types may appear in common
and equivalence provided that all of the type parameter
values are constants. This follows the existing rules for
character.