Feature Proposals for Fortran
– The complete set

by Espen Myklebust

Table of Contents

Sorry, a bug means nothing comes up here. Download the
PDF if you want a working TOC...
This document is a summary of features that I would like to nominate for inclusion into the Fortran language. They are not listed in order of importance, but in the ordered required since some features builds upon others.
My hobby horse is clearness, conciseness and expressiveness of the syntax. My take on the matter is that if some useful programmatic structure is disproportionate cumbersome to realize, one should consider if the addition of some minor language element can mend the “syntax shortcoming.”
It hope it is not necessary, but I'll say it anyway in case some interprets this document as sour moaning: Fortran is the language of my choice for most tasks due to it's mathematical and array oriented features, the increasingly available OO features, and the good built-in security provided by the modern explicit interfaces. In my use computational performance is important also, which was how I got into Fortran in the first place, after using mostly Matlab.
To a large extent the features are syntax extensions and other incremental changes and additions to the language that I find likely to make a Fortran programmer's day go a little smoother, and I hope they will be taken into consideration by those in charge of the future development of Fortran.
This document is written solely be me and is based on my experience with programming in Fortran (95 and above) and other languages, but many of the features I propose are at least inspired by what other people have proposed in miscellaneous fora on the Internet. I want to thank everyone that takes the time to read through this document, and you are welcome to contact be on myfirstname.mylastname@ntnu.no

Additional access specifications

1.1 Access specification in USE statements

1.1.1 Proposal

Possibility to prevent inheritance of USE associations through an optional access specification in the USE statement. That is, if this behavior is invoked, then:
if MODULE_B USEs MODULE_A and another scoping unit USEs MODULE_B, access to the entities of MODULE_A will not be inherited through USE association of MODULE_B (even though they are PUBLIC in MODULE_A)

1.1.2 Rationale

1.1.3 Proposed syntax

USE [[, module-nature] [,access-spec] ::] module-name [, ONLY: only-list]
USE [[, module-nature] [,access-spec] ::] module-name [, rename-list]
where access-spec is either PUBLIC or PRIVATE, and this attribute only valid for USE statements in MODULEs. Example
A number of variables types, procedures and so on is declared in MODULE_A
  REAL :: varA
MODULE_B USEs MODULE_A but declares it to be PRIVATE
  REAL :: varB
A SUBROUTINE (with an explicit interface) USEs MODULE_B
var1A is then not available to sub, along with all other entities declared in (or, generally, available to) MODULE_A.


1.2 Access specification in generic INTERFACE blocks

1.2.1 Proposal

Allow access specification in the interface statement of generic INTERFACE blocks so that separate access specification statements of these can be avoided if desired

1.2.2 Rationale

1.2.3 Proposed syntax Example of proposed syntax
PRIVATE  !module access spec
  PROCEDURE :: stest_int_32
  PROCEDURE :: stest_real_64


Read-only variables

In this section a variable is understood as an object that is stored in memory and, hence, has a memory address, without necessarily being mutable (in a particular scope). The reason is that the word constant typically refers to a Fortran PARAMETER which, at least conceptually, does not have a memory address but is “hard coded” into the program.
A similar feature proposal can be found at fortranwiki.org, and was proposed there by Joe Krahn.

2.1 Proposal

Add an attribute to flag variables as read-only (immutable), but, in contrast to to PARAMETERs, with a requirement that they be addressable to allow them as pointees. Also add a statement with the same token to declare host- or USE-associated variables as read-only in the scope of the statement.

2.2 Rationale

2.3 Proposed syntaxes

2.3.1 Attribute name

2.4 Examples

REAL, CONSTANT :: const1 = 4.0, const2 = 5.0
REAL :: var1 = 7.3
ptr => const1
ptr = 3.5  !Not allowed
ptr => const2
ptr => var1
ptr = 3.5  !Also not allowed


2.6 Additional POINTER attribute

2.6.1 Proposal & rationale

2.6.2 Comment

Extensions to IMPORT statements

3.1 Restrict the available host objects

3.1.1 Proposal

Allow IMPORT statements in internal and MODULE procedures and BLOCK constructs to restrict which named entities (or possibly only data objects) that are accessible. The default behavior (i.e. without an IMPORT statement) would be as at present, implying an IMPORT statement without an import-name-list.

3.1.2 Rationale

3.1.3 Additional proposal 1

Allow the import statement to take the form
This would provide the possibility to have non-host-associated procedures with explicit interfaces without the need for a separate MODULE to “wrap” the procedure. This will lead to increased security and less writing when no host associations are needed and it is judged that a MODULE is not strictly necessary. Comment

3.1.4 Additional proposal 2

It could be a desirable behavior that an IMPORTed variable with either the ALLOCATABLE or POINTER attribute would “lose” these, but that they can be re-obtained by naming the variable in an ALLOCATABLE or POINTER statement. Rationale Comment

3.2 Specification of intent for host associated objects

This proposal builds on the above one (section 3.1)

3.2.1 Proposal

Make it possible to specify intent (i.e. read- and/or write access) for host associated objects through the general IMPORT statement proposed above (i.e. not for INTERFACE blocks).

3.2.2 Rationale

3.2.3 Proposed syntax

3.2.4 Example

PURE FUNCTION host-fun-name( arg-list1 )
  REAL, DIMENSION( array-spec ) :: A !large array
  PURE FUNCTION int-fun-name( arg-list2 ) !A not in arg-list2
    A = expr
  END FUNCTION int-fun-name
END FUNCTION host-fun-name

3.3 Renaming

3.3.1 Proposal

Allow an import-rename-list in IMPORT statements as an alternative to the import-name-list (but only in INTERFACE blocks and not for general IMPORT statements as those proposed above).

3.3.2 Rationale

3.3.3 Proposed syntax

  IMPORT :: implemented-entity-name => host-entity-name

Read-only components in derived types

4.1 Proposal

A method to make read-only access possible for a component in a derived type

4.2 Rationale

4.3 An example

TYPE [[,type-attribute-list] ::] type-name [(type-parameter-name-list)]
  type-name, PROTECTED :: component-declaration-list
END TYPE [type-name]

4.4 Comment

Extension to the IF statement

5.1 Proposal

Extend the IF statement to allow for specification of evaluation order of the logical expressions. Alternatively, new logical operators that guarantee short-circuit evaluation of AND and OR can be added to provide an equivalent (and more general) mechanism.

5.2 Rationale

5.3 Proposed syntaxes

5.3.1 Alternative IF statement syntax

[ELSE]IF (logical-expr1) [op-token (logical-expr2)…] THEN
where op-token is either AND or OR. Comments

5.3.2 Additional operators

logical-expr1 .ANDTHEN. logical-expr2
logical-expr1 .ORELSE. logical-expr2 Comment

5.4 Examples with IF constructs

In the below block of code it is necessary to add an extra IF construct when expr2 can only be evaluated if expr1 returns .TRUE.
lvar = .FALSE.
IF (logical-expr1) THEN
  IF (logical-expr2) THEN
    lvar = .TRUE.
IF (lvar) THEN
This could however, using the proposed syntax, be vastly simplified into
IF (logical-expr1) AND (logical-expr1) THEN
Similarly, in the case that the op-token above was OR it would be equivalent to the following block of code:
lvar = .FALSE.
IF (logical-expr1) THEN
  lvar = .TRUE.
ELSEIF (logical-expr2) THEN
  lvar = .TRUE.
IF (lvar) THEN

Additional operator symbols

6.1 Proposal

Extend the set of possible operator symbols that can be used for user-defined operators to include some, or all, of the F03 special characters. Allowing composites/aggregates of the added characters and the defined operator symbols should be considered

6.2 Rationale


Additional intrinsic modules

7.1 File system operations

7.2 “I/O-options objects”

7.3 “Status objects”

7.3.1 Additionally: A library error codes and messages

Module data repository files

With repository it is intended the meaning deposition, storage or archiving of data, not data version control (for which this term is often used). Serialization, marshalling or deflating are commonly used mechanisms for furnishing this functionality.

8.1 Proposal

Introduce an intrinsic and processor independent file format that allows exporting and importing (collections of) variables in a structured manner using the variable names, and which also retains pointer associations if pointer and pointee are exported at the same time.

8.2 Rationale

8.3 Examples of proposed syntax

In an OPEN statement the keyword REPOSITORY, say, could replace FILE:
OPEN( NEWUNIT=unit, REPOSITORY=file-name [, options-specifiers] )
where options-specifiers would be an appropriate subset of the usual options, such as STATUS, IOSTAT, IOMSG, ACTION and possibly ASYNCHRONOUS, and perhaps some unique for repository files. To export a set of variables to the repository file the WRITE statement is used, and data importing is done using the READ statement:
WRITE(UNIT=unit,*) variable-write-list
READ(UNIT=unit,*) variable-read-list
The variable-write-list could contain any number of accessible variables from the module associated with the repository that unit represents.


Inter-process communication

9.1 Proposal

Intrinsic support of creating and using named pipes for inter-process communication

9.2 Rationale

9.3 Proposed syntax

Replace the FILE keyword with a PIPE keyword:
OPEN( NEWUNIT=unit, PIPE=pipe-name [, options-specifiers] )

9.4 Comment

Additional intrinsic procedures

10.1 A PRINT function

10.1.1 Proposal

Add a function for converting scalar numeric variables to character representation

10.1.2 Rationale

10.1.3 Proposed syntax

PRINT(numeric-expr [,fmt-spec])
where numeric-expr is a scalar expression of numeric type, and fmt-spec is an ordinary Fortran format descriptor which may be an asterisk or, equivalently, may be omitted. A field width in the descriptor is always ignored and is allowed to be and asterisk or a question mark, and the same goes for a repeat count as only a single numeric data entity is allowed Comments

10.1.4 Example

PRINT *, 'Here comes a number! '//PRINT(3.14,'(F4.2)')// &
', and this is the same number in scientific format'//PRINT(3.14,'(ES7.2)')

10.1.5 Addition: Allow array arguments

It could be allowed to provide array arguments to the function and an additional separator argument, a scalar character expression giving the separator between the array elements. For instance:
'This is a list of '//PRINT(size(v))//' numbers separated by “_”:'//PRINT(v,*,'_')
where the format specification asterisk defaults the formatting.

10.2 A function for testing parity of integers

10.2.1 Proposal

Add a function which tests the parity of integer an integer

10.2.2 Rationale

10.2.3 Proposed syntax

10.3 A function for testing sign

10.3.1 Proposal

Add an elemental function for testing the sign bit of (intrinsic) numeric types, returning a logical value corresponding to the sign

10.3.2 Rationale

10.3.3 Proposed syntax

10.3.4 Proposed return value

10.3.5 Examples

In an iteration using the logarithm for computing the relative difference between two consecutive values
DO WHILE ( STEST(var_1) .EQV. STEST(var_2) ) AND ( LOG(var_1/var_2) .GT. tol )
where the syntax proposed in section 5 has been used. To test if two complex numbers are in the same quadrant would amount to

10.3.6 Additional proposal

Allow the second argument to SIGN to be of LOGICAL type; the interpretation should be consistent with that of STEST. An example of usage is when one wants to either add or subtract something depending on some condition, e.g. if an INTEGER is even or odd; this could be written in a very clear and concise manner as
RES = -A
DO i = 2, n
instead of the lengthy
RES = -A
DO i = 2, n
    RES = RES - A
    RES = RES + A

10.4 A function for comparing a subset of bits

10.4.1 Proposal

Add a function for comparing a (contigious) subset of bits for numeric data types. The most frequent usage in practice would probably be to compare the most significant part of the numbers, and this limitation will be implied in this proposal, but needs not necessarily be a restriction if other uses are desired.

10.4.2 Rationale

10.4.3 Proposed syntax

10.5 The base 2 logarithm

10.5.1 Proposal and rationale

10.5.2 Proposed syntax

10.6 Function for taking roots

10.6.1 Proposal and rationale

10.6.2 Proposed syntax

10.7 Specialized implementations of common functions

10.7.1 Proposal

Add specialized implementations of standard functions where particular “forms” of the argument may suffer catastrophic cancellation in a standard implementation

10.7.2 Rationale

10.7.3 Examples of functions and proposed syntaxes

When X is small compared to one the forms on the lhs. of each equality should be used in place of the rhs.:
where the equality is meant in an analytical sense! (Numerically the equalities would normally evaluate to false)

10.7.4 Additional functions

Extensions to intrinsic procedures

11.1 Extend the FINDLOC function

11.1.1 Proposal

Allow a POINTER argument as an alternative to VALUE. The function result should be the vector of subscript positions identifying the element associated with the POINTER. The argument associated with the POINTER argument must be a scalar pointer.

11.1.2 Rationale Comment

11.2 Extend the domain of predefined indices

With predefined indices it is meant any index with a predefined lower bound. Array subscripts are not in this category since the lower bound is not restricted to a defined value

11.2.1 Proposals

Allow the DIM argument in array intrinsic procedures to take non-positive values with the interpretation that 0 is the last element, and a negative argument counts down from the second last towards the first element.
Allow substring starting and ending points to take non-positive values with the interpretation that 0 is the last character, and a negative argument counts down from the second last towards the first character.
Allow the POS argument in the intrinsic bit computation/manipulation procedures to take negative values with the interpretation that -1 is the last bit, -2 the second last, and so on.

11.2.2 Rationale

11.2.3 Comment


Below are some proposals regarding the initialization of values to variables in procedures. There might be a more far-reaching meaning attached to the word “initialize” when used in relation with Fortran, possibly regarding if it is possible to accomplish at compile-time or not. Here, though, it is used in the meaning “the initial value” (this term is used repeatedly in the Fortran standard(s) in the same meaning as intended here) a variable has when referenced in the executable part of a (sub-) program.

12.1 Dummy arguments

12.1.1 Proposal

Allow initialization for dummy arguments with INTENT(OUT), and for any OPTIONAL argument with the effect that a missing argument is initialized to the assigned value. The behavior will differ from other (explicit) initializations by not having an implied SAVE attribute.

12.1.2 Rationale


12.2 Regarding implied SAVE

The present rules about (explicit) initialization of variables and the implied SAVE attribute, as well as default initialization, creates considerable confusion among many Fortran users (and not only the newbies!), which is apparent from the many lengthy Internet forum discussions. Presented below are two alternatives to help sort this out.

12.2.1 Alternative 1

Add a constraint in the standard that compilers must be able to issue a warning or error (depending on the option/switch) for any initialized variable (that implicitly acquires the SAVE attribute) that do not have the SAVE attribute. It must be considered good programming practice to explicitly declare all variables that are saved with the SAVE attribute, especially to assist (code) readers not familiar with all fine details of the language. This would be the same behavior as for default initialized module variables at present (at least up to F03).

12.2.2 Alternative 2

Add a constraint in the standard that compiles must have an option to choose whether or not to add an implicit SAVE attribute to non-module variables, so that this attribute must be added explicitly to obtain the present behavior. This is the more radical alternative, but should be the preferred as it is the most logical behavior (judging by most forum posts from users unaware of the present behavior) as the SAVE attribute actually exists in the language. As the present behavior would still be available through the proposed option, all existing code would still be compilable, and it could be combined with another option to issue a warning when unsaved variables are initialized in the declaration in order to help the transition for users that are accustomed to the now standard behavior. Comments

12.2.3 Additional proposal to alternative 2

If SAVE is not implied by initialization one could allow restricted expressions (termed general specification expressions in [2]) to be used for value initializations

12.3 Automatic arrays

12.3.1 Proposal & rationale

Allow scalar initialization expressions (or scalar restricted expressions if the previous proposal in this section is approved) to be used to initialize automatic arrays since the expression would be compatible with the variable regardless of the array extents. The same would probably be possible for default initialization of array components in derived types with extents given by LEN type parameters.

12.3.2 Example

FUNCTION foo(a,b)
REAL, DIMENSION(a,b) :: c = 1.

12.3.3 Additional proposal

Require that compilers have (at least) an option to allocate automatic arrays in the pool/heap/? if they are too large for the stack. Put differently: require safe memory allocation for automatic arrays.

Extension to the specification of shape for automatic arrays

13.1 Proposal

Allow a MOLD argument for the array specification in the DIMENSION attribute of an automatic array.

13.2 Rationale

13.3 Additional proposal

In the case that “initialization” without the SAVE attribute behaves as proposed in section 12.2, ie. without the implied-SAVE behavior; if an automatic array is initialized using a previously declared array or dummy argument array, DIMENSION(*) should be allowed since a dimension specification is redundant in that case. (This is analogous to the F08 syntax for PARAMETERs)

13.4 Example of proposed syntaxes

FUNCTION foo(arr)
REAL, DIMENSION([MOLD =] arr) :: foo
REAL, DIMENSION(*) :: temp = 2*arr   !no implied SAVE

13.4.1 Comment

Extension to the INTENT attribute

This feature proposal is more or less “snipped” from the Feature Proposals page at fortranwiki.org, and was proposed there by the user Max.

14.1 Proposal

Allow INTENT(NONE) to signal a dummy dummy-argument.

14.2 Rationale

14.3 Additional extension

In the case that specification expressions are allowed in value initializations (see section 12.2.3) dummy arguments with INTENT(NONE) could be allowed used in the specification part still, and usage would be prohibited only in the execution part.

14.3.1 Comment

14.3.2 Example

Often it is desired to use a specific (typically higher than default) precision and/or range in the internals of a procedure, such as when numeric iterations are performed or when intermediate results are expected to be much larger than the final result.
FUNCTION func(a,b,c)
REAL(lp) :: func
REAL(lp), INTENT(NONE) :: a,b  !low precision
INTEGER,INTENT(IN) :: c  ! c > 0 ^ |LOG(c)| >> 0
REAL(hp) :: a_hp = a  !or REAL(a,hp)
REAL(hp) :: b_hp = b  !or REAL(b,hp)
func = (a_hp**c + b_hp**c)**(1./c)

Implicit generic INTERFACEs

15.1 Proposal

Allow MODULE PROCEDUREs to be defined using identical names as long as they satisfy the rules for inclusion into a generic interface, and let the compiler create the appropriate generic INTERFACE automatically.

15.2 Rationale


Identical FUNCTION and SUBROUTINE names

16.1 Proposal

Allow a FUNCTION and a SUBROUTINE to have the same name.

16.2 Rationale

16.3 Addition: Subroutine forms of some intrinsic functions

This feature may require that non-intrinsic functions and subroutines are allowed to have the same name, as proposed in section 16, but it may also be independent of that proposal since this one concerns intrinsic procedures exclusively.

16.3.1 Proposal

Add “subroutine forms” of certain intrinsic functions so that the operations are done in-place.

16.3.2 Rationale

16.3.3 Examples of eligible functions

New syntactic functionality for assignment statements

17.1 Proposal

Allow a special character to be used in place of the designator for the variable on the l.h.s. of an assignment statement in the expression on the r.h.s.

17.2 Rationale

17.3 Proposed character

17.3.1 Examples

Listed below is three assignments with plausibly increasing difficulty of optimization:
idx = @ + 5
arr(3:idx) = @*2
arr = [@, -@]
from a trivial case (I hope!), via an array operation on an array section, to a reallocation where, when the proposed syntax is used, it should be obvious to the compiler that an optimization should be attempted. For the above examples the proposed syntax, although convenient, is not essential, in contrast to the next example where fun is an impure function (so that it may not return the same value every time it is called by the same argument):
arr(fun(i)) = arr(fun(i))*2 !an unintended array element may updated
arr(fun(i)) = @*2           !the intended array element is updated
The following lengthy assignments
array(i,j)%comp1(k,l)%value1 = ABS(array(i,j)%comp1(k,l)%value1 &
- SQRT(array(i,j)%comp1(k,l)%value1))
array(i,k)%comp1(j,l)%value2 = ABS(array(i,k)%comp1(j,l)%value2 &
- SQRT(array(i,k)%comp1(j,l)%value2))
would be written simply as
array(i,j)%comp1(k,l)%value1 = ABS(@ - SQRT(@))
array(i,k)%comp1(j,l)%value2 = ABS(@ - SQRT(@))
The chance of producing a typo if the second statement is made by copying the first statement and just altering the subscripts, is practically eliminated.

17.4 Comment

New array qualification notation

18.1 Proposal

Allow square brackets to be used when referencing array sub-objects.

18.2 Rationale

18.3 Proposed syntax

array-name[ subscript ]



Extension to subscript specifications

19.1 Proposal 1

Allow logical rank 1 arrays to be used as masks when creating an array section; they will be referred to here as section masks.

19.1.1 Rationale

19.2 Proposal 2

Allow two triplets in array subscript specifications, one spesifying which array elements to include and one spesifying which array elements to exclude

19.2.1 Rationale

19.2.2 Proposed syntax Comments

19.2.3 Example of usage for rank 1 arrays

To create a vector containing all the elements of vec except those with a subscript value of 3, 6, 9, and so on:
vec3 = vec[ : \ 3::3 ]
To assign values to all array elements with an even numbered index, except for those evenly divisible by 6
vec[ 2::2 \ 6::6 ] = vec2
In order to perform the first operation at present, one will have to resort to vector subscripting or a DO loop, whereas the next statement is only possible through a DO loop. The proposed syntax makes it possible to use simple syntax to express these simple operations.

Extensions to array constructors

20.1 Triplets in array constructor specifications

20.1.1 Proposal & rationale

Allow a Fortran triplet to be used in array constructors for the particular, but quite common, case:
[[type-spec ::] triplet-spec-list]
where a “trivial” implied DO otherwise has to be used.

20.2 Stacking arrays

20.2.1 Proposal

Introduce a new array constructor to stack (conformable) arrays

20.2.2 Rationale

20.2.3 Proposed syntax

[/ ext-ac-spec /]
and one could additionally allow the analogous extension to the “legacy” array constructor
(// ext-ac-spec //)

20.2.4 Examples

REAL, DIMENSION(5) :: x,y,z
REAL :: a(5,3), b(5,4,3), c(5,3,4), d(5,3,12)
a = [/ x, y, z /]
d = [/ a, (b(:,i,:),i=1,3), (a,c(:,:,j),j=1,4) /]
where the array implied DO operates on the conformable 5-by- 3 rank 2 arrays.

Manipulation of allocatable arrays

New mechanisms for manipulating the size of allocatable arrays while keeping the original values are proposed.

21.1 A REALLOCATE statement

21.1.1 Proposal & rationale

21.1.2 Statement syntax

REALLOCATE(array-name(alloc-shape-spec-list)) Comment

21.1.3 Example

where, after the reallocation is done, the values in the array section arr[:5,:2] will be the same as before the resizing.

21.1.4 Comment

21.2 A RESIZE subroutine

21.2.1 Proposal & rationale

21.2.2 Calling syntax

CALL RESIZE( SOURCE=array-name, EXTENT=scalar-integer-expr [, STAT]) Comment Examples
and here it is possible to just change the array descriptor without any copying of data since the resized array is just an array section of the original one.

Object pseudo-components

Allow intrinsic inquiry functions to be accessed through pseudo-component syntax when no optional arguments are needed (along the same lines as the F08 %re and %im pseudo components for COMPLEX variables)

22.1 Array pseudo-components

22.2 String pseudo-components

Qualification of temporary objects

23.1 Function-result qualification

23.1.1 Proposal

Allow referencing an array element or a type component from a function result without storing it to a temporary variable first.

23.1.2 Rationale

23.1.3 Proposed syntax

where the pipe character is used to “pipe the result” entity to a (hidden) temporary variable that can be qualified as usual. Comment

23.1.4 Example

If a procedure returns a derived type which has a bound function a function composition can be performed which is not otherwise possible without using explicit temporary objects. For instance:
c = fun1(arg-list1)|%tb-fun2(arg-list2)|%tb-fun3(arg-list3)
would be equivalent to the following code:
a = fun1(arg-list1)
b = a%tb-fun2(arg-list2)
c = b%tb-fun3(arg-list3)

23.2 Array constructor qualification

23.2.1 Proposal & rationale

23.2.2 Proposed syntax

[ ac-value-list ]|[ subscript-list ]
[ ac-value-list ]|%component-spec
and with the extended array constructors proposed in section 20 remapping of subscript indices from possibly non-default lower bounds to default using the syntax
[/ ext-ac-value-list /]|[ subscript-list ]

Notation for sets & sequences

For some of the features that are proposed further down in this text a new notation/syntax is believed to be advantageous. It is not pivotal to the functionality and could be replaced by ordinary array constructors, but it greatly improves semantics by making the distinction to arrays evident. It is treated separately here for clearness, and specific examples will appear where the respective features are described

24.1 Proposal

A notation to explicate that a collection of objects of the same type, which at present would typically be grouped into an array, should be treated as a collection of individual members, possibly ordered, resulting in the mathematical notions of sets, multisets and sequences depending on the area of application.
In this connection an array is presumed interpreted as a single, index qualified, (homogeneous) composite object, analogous to how a scalar instance of a derived type is a single, name qualified, (possibly) inhomogeneous, composite object. Put differently: all elements in an array should ideally have the same units (if any, and in a “composite sense” for composite types) which is necessary if array operations such as multiplication with a scalar and summing all the elements shall be meaningful.
It is emphasized that the proposal is limited to syntax/notation and is not a new data structure type (see section 44 for such proposals).

24.2 Rationale

24.3 Proposed syntaxes

24.3.1 Definition

{[type-spec ::] set-spec}
where set-spec (set is used here and after to mean both sets and sequences) is either one of the following and all of the above entities may be variables or (literal) constants or combinations of such ones. The order of the set members, if needed, is the array element order for an array (equivalent to if the array was wrapped in an array constructor), and the “natural order” for the two others. Comments Examples of allowed forms Comment

24.3.2 Referencing set members

associate-name => {set-spec}
which is meant to be an extension to the syntax used in ASSOCIATE constructs, the rationale being that set syntax is to be used where a single name should designate multiple entities, one at the time. A set containing only a single data entity would be equivalent to an ordinary variable selector, the only difference being the curly brackets (which in that relation would have the same effect as parentheses, i.e. none).

24.3.3 Subsections of sequences

To be able to reference only a sub-sequence is useful for about the same reasons as qualifying array constructors (cf. section 23.2), and it would be natural to allow the syntaxes
where for the last syntax the first pair of curly brackets represent the set/sequence constructor and the latter the qualification of the constructed object.

New syntax for iterated DO loops

25.1 Proposal

Add a new syntax for declaring a DO statement loop-control that follows the pattern of modern Fortran. This syntax will be further enhanced with subsequent syntax proposals

25.2 Rationale

25.3 Proposed syntax

[do-construct-name:] DO [,] FOR( [type-spec ::] index-spec-list &
[, scalar-mask-expr] )
END DO [do-construct-name]
This matches the DO CONCURRENT syntax exactly, with the obvious difference in the “DO-keyword.” However, if more than one index variable is specified there must be a rule for determining in which order the indices are incremented, in contrast to the case for a DO CONCURRENT construct where this does not matter. The following rule is suggested:
The leftmost index declared is incremented first, then the second leftmost and so on.
This is consistent with how the subscript order value increases in array element order which have a pleasant implication when looping through arrays.

25.3.1 Example

The following loop
DO j=1,m
  DO i=1,n
    IF ( i.LT.n .AND. j.LT.m ) THEN
      a[i,j] = a[i,j] + a[i+1,j+1]
    END IF
could be written much more compactly as
DO FOR( i=1:n, j=1:m, i.LT.n .AND. j.LT.m )
  a[i,j] = a[i,j] + a[i+1,j+1]
In both loops the indices are specified in the order that should(?) achieve the best performance, but whereas for the present syntax the outermost construct (usually declared first?) must have the last index and the innermost construct the first one, the proposed syntax declares the indices in the same order as they (should!) appear in the array qualifier. This is perhaps a minor detail (that some compilers automatically mend), but in the writers experience, at least beginners and those that are not aware of this, tend to declare the nested loops “in the reverse order.” Of course it would also be possible to maintain the structure of the first code block, only changing the loop-control parts to the new syntax, as shown below
DO FOR( j=1:m )
  DO FOR( i=1:n )


25.4 Additional extensions

25.4.1 Modern implied DO

The modern triplet syntax could also be used in an implied DO specification, with the obvious candidate syntax
( do-value-object-list, do-variable = int-expr:int-expr [:int-expr] )
where the do-value-object-list can be another implied DO specification or a list of values or objects (with the same rules as for the present types of implied DO specifications).

25.4.2 Control variable value collection

This proposal is just a special case of a more extensive proposal in section 27, but it is presented here due to its fundamentality and commonness Proposal
It could be allowed to use an array of an INTEGER type, possibly restricted to rank 1, instead of a triplet to specify the index values. Rationale Example of proposed syntax
Specifically, the proposed feature would simplify the following type of code
DO, FOR( i=1:n )
  j = arr[i]
into the one-line statement
DO FOR( i=arr )
with additional savings/simplifications when there are additional indices. Comments

25.4.3 Indefinite-DO iteration control Proposal
Allow a scalar integer control variable for indefinite DO loop constructs to limit the maximum possible number of iterations Rationale Proposed syntax
[do-construct-name:] DO [(scalar-integer-expr)]
END DO [do-construct-name]

25.4.4 Loop statements Proposal
Allow DO loops that are using the “modern loop-control” to have a statement form as long as the loop body can be expressed in a single line. Rationale Examples of proposed syntaxes
DO FOR( i=1:n, j=1:m, i.LT.n .AND. j.LT.m ) a[i,j] = a[i,j] + a[i+1,j+1]
DO CONCURRENT (i=1:n, j=1:m) a[i,j] = a[i,j] + alpha*b[i,j]
Mainly for consistency, a DO WHILE statement should also be allowed, since it's use may be somewhat limited. Nevertheless, a single-line DO WHILE can at times serve the purpose, such as
DO WHILE (a.LT.b) a = a*f
when all the variables are of integer type. If it can be assumed that log ( b a ) log (f) is not very large, this simple statement may be both useful and efficient, and it conveys clearly its objective compared to
a = a**(CEILING(log(REAL(b)/a)/log(REAL(f)))) Comments
Example of proposed additional syntax
FOR (loop-control) DO
CONCURRENT (loop-control) DO
WHILE (scalar-logical-expr) DO

Implicitly typed control variables

26.1 Proposal

Make index/control variables implicitly typed to default INTEGER if they are not declared, or they are declared to a non-INTEGER type.

26.2 Rationale

26.3 Proposed syntax

DO [,] FOR( [ [INTEGER](type-param) ::] index-spec-list [, scalar-mask-expr])
DO [,] CONCURRENT( [ [INTEGER](type-param) ::] index-spec-list [, scalar-mask-expr])
FORALL( [ [INTEGER](type-param) ::] index-spec-list [, scalar-mask-expr])

26.3.1 Comments regarding the present DO loops

Automatic control-variable specification

27.1 Proposal

Often the index/control variable(s) in a loop or a FORALL construct or statement will need to take precisely all the values between LBOUND(array,dim) and UBOUND(array,dim), and as this so often is the case a shorthand syntax is proposed to simplify writing the code for achieving this.

27.2 Rationale

27.3 Proposed index-spec-list syntax

index-list, [MOLD=] array-name[[index-assoc-list]]
index-list, [MOLD=] array-name[(index-assoc-list)]
where index-list is a list of indices, and the first line uses the array qualification proposed in section 18 whereas the last uses the present standard syntax. The index-assoc-list is optional since each index in index-list is implicitly associated with the array dimension corresponding to the index's placement in that list if index-assoc-list it is missing, but it may be used to associate an index with another array dimension.

27.3.1 Examples

FORALL( i,j,k, MOLD=array3d )
DO CONCURRENT( i,j, array2d[i,j], i.NE.j )
DO FOR( i,j, array3d[i,j,i] )

27.3.2 Rules

27.3.3 Extension 1

Allow implicit triplet specifications where only the values of the omitted subscripts are taken from the MOLD argument. Example of syntax
FORALL( i=10,j=:10,k=2::2, MOLD=array3d )

27.3.4 Extension 2

Allow qualification of the MOLD array section, using the syntax proposed in section 23, to specify the index-assoc-list. This would be useful in the case that the number of index variables differs from the array rank. Example of syntax
FORALL( i,j, MOLD=array3d[3:,1:5,:]|[i,j,j] )

Automatic, generalized iterators

28.1 Proposal

A syntax that allows “automatic looping” through all the elements in an array or array section, without the use of control variables, is proposed.

28.2 Rationale

28.3 Proposed syntax

DO [,] loop-type (set-assoc-list)
where loop-type is either FOR or CONCURRENT, and an element in the set-assoc-list is on the form
iterator => {obj-set}
where iterator is local to the loop construct and associated with each object in the set obj-set exactly once during the execution of the loop. obj-set is any valid set of objects, as defined in section 24. When the loop is of an ordinary DO FOR type and the obj-set is an array (possibly of rank greater than 1), the iterator sequence order will be the same as for the set: the array element order.


28.4 Examples

The following loop
can alternatively be written as
DO CONCURRENT(cmp => {dt_arr(:,3)%comp})

28.4.1 Comment

Extended availability of array argument bounds

This feature proposal is only meaningful if an assumed-shape dummy array with the CONTIGUOUS attribute does not “inherit” the array bounds of the actual argument.

29.1 Proposal

Add an attribute to indicate that the array descriptor of a dummy argument should be available to a procedure for contiguous, non-deferred shape arguments

29.2 Rationale

29.3 Proposed syntax

29.3.1 Attribute name

29.4 Comment

29.5 Additional proposal

A special syntax for specifying the section of a (simply?) contiguous array that has a section-subscript-list which specifies a simply contiguous section could be helpful for the programmer, and possibly also for the compiler

Additional functionality for the RETURN statement

30.1 Proposal

It should be possible to have an assignment statement following directly after the RETURN statement (on the same line). For FUNCTIONs it could be possible to allow more general statements and expressions with the implied meaning that the result from this expression should be returned by the function instead of the return variable. For SUBROUTINEs only an assignment statement should be allowed (in addition to the scalar integer expression presently allowed).

30.2 Rationale

30.3 Examples of proposed syntaxes

Set/change the value of a dummy argument when returning from the procedure:
[IF (logical-expr)] RETURN status = 4
To return the square root of the variable var from the function:
[IF (logical-expr)] RETURN SQRT(var)
where var can be either a local variable, a dummy argument (with any INTENT) or the name of the result variable (or function name). Next; only a subsection of the array returned by the function fcn is returned
[IF (logical-expr)] RETURN fcn[:n1,:n2]
There is no method of achieving this result with a non-allocatable function(?), and although it could be possible using the proposed mechanism for qualifying an array valued function result (cf. with section 23) it would be necessary to know the upper bounds (i.e. n1 and n2) outside the function. The following code illustrates a (dirty?) way to accomplish this:
but it requires fcn to be impure so that the upper bounds be set inside the function.

A RANK attribute

A similar feature proposal can be found at fortranwiki.org, and was proposed there by Joe Krahn.

31.1 Proposal

Add an attribute that may be used instead of DIMENSION when the array bounds are unspecified, i.e. when colons are used just to indicate the rank.

31.2 Rationale

31.3 Proposed syntax

type-spec, [attr-list,], RANK(rank) :: variable-declaration-list

31.4 Comment

31.5 Addition: RANK inquiry function

The rank of an argument is often useful, and so an array function to inquire about the rank, namely
RANK(array) equivalent to SIZE(SHAPE(array))
could be added to allow effective and clear syntax. It should also be available using pseudo-component syntax, i.e array%rank (cf. with section 22.1)

31.5.1 Comment

31.6 Addition 2: array shape specification

When an array is declared using the RANK attribute it could be allowed to let DIMENSION take a vector “argument” for specifying the array SHAPE. The vector length must then be constant and equal to the rank, eg.:
INTEGER, [RANK(1),] DIMENSION(r) :: vector
REAL, RANK(r), DIMENSION(vector) :: array


Rank-indifferent procedures

32.1 Proposal

By rank-indifference it is meant that the rank of an entity is not significant. A syntax that allows for writing rank-indifferent procedures, similar to the intrinsic ones, should be available when the calling interface is explicit.

32.2 Rationale

32.3 Proposed syntax

proc-spec(dummy-argument-list) [procedure-suffix]
type-spec, RANK(*) [,attr-list] :: dummy-argument-declaration-list
type-spec, ALLOCATABLE, RANK(*) [,attr-list] :: variable-declaration-list
Here the proc-spec is the usual “header” in a FUNCTION or SUBROUTINE definition (except that ELEMENTAL is not allowed), and the same goes for procedure-suffix. An allocatable variable must be allocated using either automatic allocation (and possibly de- and reallocation) by assignment, or using the MOLD or SOURCE keyword:
ALLOCATE(temp, MOLD=arg)


32.3.2 Array sub-object access

32.4 Examples

PURE FUNCTION norm1(array)
REAL, RANK(*), INTENT(IN) :: array
norm1 = SUM(ABS(array))

32.5 Addition: Rank-indifferent array sub-object access

32.5.1 Proposal

Allow using a single index, the subscript order value, for accessing array-elements/sections in rank-indifferent procedures (what is sometimes called linear indexing).

32.5.2 Rationale


ASSOCIATE statement

33.1 Proposal

Allow solitary ASSOCIATE statements, i.e. the ASSOCIATE( association-list ) part of an ASSOCIATE construct (but without the possibility of a construct name), in the specification part of a subprogram or BLOCK construct, with the interpretation that the specified associations pertains to the whole scope.

33.2 Rationale


Procedure association

Allow selector expressions in ASSOCIATE constructs to have deferred procedure arguments which will be dummy arguments of an associate-name procedure.

34.1 Rationale

34.2 Proposed syntax

For ASSOCIATE constructs, the following association is proposed added:
where all the arguments specified in the assoc-dummy-arg-list must be present in the as arg-list well.


34.3 Example

The function func may be referenced with the alternative name fun, where two of the arguments are already specified, and ditto for the subroutine subr
ASSOCIATE ( fun(x) => func(2.71,x,var1), sub(y) => subr(var2,y) )
a = fun(3.14), b = fun(-7.)
CALL sub(fun(12.,var2))
In addition func could be associated with yet another function, with the same deferred argument but with different prespecification of the two remaining ones. To achieve this at present one will have to use two differently names but otherwise identical “interface functions,” and this will get worse as the number of “non-general instances” of func increases.


34.4 Extension: Allow general expressions

34.4.1 Proposal

Allow general expressions in the proposed procedure association for creating single statement, scalar functions

34.4.2 Rationale

34.4.3 Proposed syntax

ASSOCIATE( [type-spec ::] proc-assoc-name(dummy-arg-spec-list) => assoc-expr )

34.4.4 Example

ASSOCIATE( steps(REAL :: x, y) => INT(var1*EXP(x) - var2*EXP(-y)))
where the arguments are both REAL while the result will be scalar INTEGER as inferred from the expression.

Parametrized procedure interfaces

Even in the case that a more advanced macro-feature would be included into the standard, it is the opinion of the writer that the proposed method would be so easy to use, and also to implement, that it still deserves consideration.

35.1 Proposal

A simple method for doing basic generic programming, which builds on the existing Fortran type (or kind) parametrization framework, is proposed. The method is basically an automation of something that is often fairly straight forward, but somewhat time consuming, to obtain at present.

35.2 Rationale

35.2.1 A method for creating parametrized procedures at present

  1. Write the procedure source code in a separate file, using unique names for all type parameters that need to be varied independently, and a procedure name different than the intended generic name
  2. Create a MODULE containing a generic interface block for procedure and a specific combination of the type parameter values
    1. Make all entities PRIVATE, except for the generic procedure name
    2. INCLUDE the procedure source code
    3. Duplicate the MODULE the number of times necessary cover all the desired type parameter combinations
  3. Create a MODULE where all the previous modules are USEd

35.3 Proposed syntax

The set notation introduced in section 18 is used in an ASSOCIATE statement (cf. with section 33)
proc-spec(dummy-argument-list) [procedure-suffix]
ASSOCIATE (param-assoc-list)
type-spec [[,attr-list] ::] dummy-argument-declaration-list
type-spec [[,attr-list] ::] variable-declaration-list
In the first line in the declaration part, or possibly following any needed USE statements, an ASSOCIATE statement appears. Each parameter association in the param-assoc-list takes the form
param-name => {param-set}
where param-set is either a comma separated list of PARAMETER names and/or literal constants, or an array containing valid parameter values. There may be several ASSOCIATE statements, possibly mixed with USE statements, but preceding any type declarations. For each combination of parameters, when one is picked at a time from each parameter set, a specific procedure is compiled, using an undefined name which is not accessible to the program.

35.3.1 Comment

35.4 Example

SUBROUTINE subroutine-name(arg1,arg2,arg3) [procedure-suffix]
ASSOCIATE (int_kind => {ik1,ik2}, real_kind => {rk1,rk2,rk3}, ranks => {0,1,2})
INTEGER(int_kind) :: arg1
REAL(real_kind), RANK(ranks) :: arg2
TYPE(dtype(int_kind,real_kind,rank)) :: arg3
with the following interpretation: int_kind takes the values of ik1 and ik2 and, independently, real_kind takes the values of rk1, rk2 and rk3. This makes for 6 combinations of type parameters, and with the additional rank parameters a total of 18 specific procedures will be compiled


Alternative interfaces for module procedures

This proposal is independent of, and in a sense conjugate to, the proposed procedure parametrization feature, but to emphasize how they can be used together some of the below examples include use of parameter parametrization.

36.1 Proposal

A method to simplify creation of generic procedures for which a common procedure body could be used with different procedure calling arguments. In this a “canonical” ordinary procedure is extended by using specific interfaces which converts and/or maps the alternative arguments to match the canonical ones. The canonical procedure will be termed the basis procedure, and the ones with alternative arguments, derived procedures.

36.2 Rationale

36.3 Proposed syntax

Two syntaxes are proposed for declaring the alternative arguments.

36.3.1 Alternative 1

The first one adds a dummy argument list after the (generic-to-be) procedure name
INTERFACE generic-proc-name(dummy-arg-list)
  [ASSOCIATE (param-assoc-list)]
  ASSOCIATE (argument-assoc-list)
END INTERFACE [generic-proc-name]
The interface body is similar to the specification part of an interface body, whereas the subprogram heading is omitted (or rather merged into the interface statement by ) since no new information would come from it. With this syntax only one INTERFACE may be specified within each “interface block,” but all blocks with the same basis procedure, i.e. identical generic-proc-name, will be known by this name as if they were all declared in a generic interface block. If this procedure name, with all its associated specific procedures specified through the above syntax, should be part of an even “larger” generic interface (as a nested generic interface) it would be declared in a procedure-statement in a generic INTERFACE as usual.

36.3.2 Alternative 2

The second proposal for a syntax is a kind of merging of the separate-interface-body and the procedure-statement :
MODULE PROCEDURE generic-proc-name(dummy-arg-list)
  [ASSOCIATE (param-assoc-list)]
  ASSOCIATE (argument-assoc-list)
END [PROCEDURE [generic-proc-name]]
Here the MODULE PROCEDURE statement has become a block instead, and several can be included in the same interface block as usual. One can alternatively view the syntax as an extension to the separate interface body in that PROCEDURE keyword is used in stead of FUNCTION or SUBROUTINE, since that information (together with any other characteristic of the procedure) would be associated with the definition of generic-proc-name. If it is desired that more procedures be known by the generic-name, this is achieved in a straight forward manner by including more interface bodies and/or procedure statements.

36.3.3 Examples

The following function will be generalized to accept miscellaneous other kinds of arguments
FUNCTION func1(arg1,arg2)
  ASSOCIATE (realkind => {4,8,16})
  REAL(realkind) :: arg1, func1
  REAL(realkind), DIMENSION(:) :: arg2
Example where a single array is provided instead of arg1 and arg2:
INTERFACE func1(array)
  REAL(realkind), DIMENSION(:) :: array
  ASSOCIATE ( arg1 => array(1), arg2 => array(2:) )
This version of func1 inherits the parametrized kind parameter realkind, and so it is available with all the same parameters as the basis function. It could also be possible to swap which one was the basis and which was the derived by using an array constructor in the ASSOCIATE statement: array => [arg1, arg2].
Below is an example of a generic interface (nested; since func1 will also be generic) combining the second proposed syntax and an ordinary procedure-statement:
  MODULE PROCEDURE func1(array)
    REAL(realkind), DIMENSION(:) :: array
    ASSOCIATE ( arg1 => array(1), arg2 => array(2:) )
  MODULE PROCEDURE func1(comp_arg)
    TYPE(typ1) :: comp_arg
    ASSOCIATE ( arg1 => comp_arg%cmp1, arg2 => comp_arg%arr(1:typ1%cmp2) )
  MODULE PROCEDURE func1(iarg1,iarg2)
    ASSOCIATE (intkind => realkind/2)
    INTEGER(intkind) :: iarg1, iarg2
    ASSOCIATE ( arg1 => REAL(iarg1,realkind), arg2 => [REAL(realkind) :: iarg1, iarg2])
  [MODULE] PROCEDURE :: func2, func3  !these may or may not be module procedures
The first interface-body is the analogous to the previous example. In the second the components of a derived type is associated with the original arguments, and the type and kind parameters of these must match those of exactly one of the specific basis procedures. In the last interface-body a parametrization is made, based on the parametrized realkind parameter, to make a number of specific derived functions accepting integer arguments. Each of the specific basis functions has a corresponding derived function where the intkind parameter has a value half that of the realkind parameter.


Array of pointers to scalar entities

37.1 Proposal

Add an attribute to declare that a pointer's target(s) is (are) scalar. Specifically, in the case that a DIMENSION or RANK attribute is given, it is associated with the pointer structure itself.

37.2 Rationale

37.3 Proposed syntax

37.3.1 Attribute name

37.3.2 Examples of declarations

A special attribute list, the scal-attr-list, is used in the following examples which differs from any other valid attribute list only in that it cannot include DIMENSION (or RANK). This is intentional to emphasize the the array cases which are the important ones here.
type-spec, [scal-attr-list,], POINTER, SCALAR :: variable-declaration-list
which is no different than the present scalar pointer declaration apart from the SCALAR attribute which is allowed for consistency. Next the array cases:
type-spec, [scal-attr-list,], DIMENSION(colon-list), POINTER, SCALAR :: var-decl-list
type-spec, [scal-attr-list,], RANK(rank), POINTER, SCALAR :: var-decl-list
Specifically, the scal-attr-list may include an ALLOCATABLE attribute, which naturally pertains to the pointer structure.

37.3.3 Special array-of-pointers assignment

An array of scalar pointers could be collectively associated with the corresponding elements in a set using the syntax
scalar-pointer-arr => {set-spec}
where set-spec must have TARGET members only (i.e. a triplet is then automatically forbidden). If set-spec is an array, the set notation clearly signifies that it is the array elements, i.e. the set members, that are the targets, and not the array itself. The key difference between such a (collective) pointer association an that between an array and an array pointer is that here each pointer may be subsequently re-associated to another scalar, so that it may be regarded more as a collective pointer association statement. If the scalar-pointer-arr is ALLOCATABLE it will become a rank1 array with size/extent equal to the number of members in set-spec, unless set-spec consists of a single array, possibly of rank greater than 1, in which case it will have the same shape with all lower bounds equal to 1. Even though a set is shape-less this seems like a natural behavior in the specific case, and, furthermore, automatic de- and reallocation should be allowed if the shape of the “array set” does not match the shape of the pointer array.

37.4 Examples

TYPE :: real_ptr
  REAL, POINTER :: num
END TYPE real_ptr
REAL :: a
TYPE(real_ptr), DIMENSION(n) :: real_ptr_arr
real_ptr_arr(1)%num => a
real_ptrs(1) => a
The num component lengthens the statement and it seems artificial when what is desired is just an array of (pointers to) REALs. Likewise, if the derived type POINTER component was a derived type, the actual TARGET component would have to be preceded by the actual POINTER component name, and this is easily forgotten when the “path” becomes long (which, almost ironically, may be the result of the very issue addressed here).


Parallel types

38.1 Proposal

An attribute to declare that a component of a derived type should be stored in “parallel” when a variable of that type is array valued. Also a corresponding statement to declare that all the components in a derived type should be treated in this way.

38.2 Rationale

38.3 Proposed syntax

38.3.1 Attribute name

38.4 Example

A 2-by-2 matrix type intended to be used in a array form as a collection of 2-by-2 matrices
TYPE :: matrix2
  REAL, DIMENSION(2) :: eigval
END TYPE matrix2
or by type extension using the proposed parallel statement
TYPE :: par_mat_2
  REAL :: c11
  REAL :: c21
  REAL :: c12
  REAL :: c22
END TYPE par_mat_2
TYPE, EXTENDS(par_mat_2) :: matrix2
  REAL, DIMENSION(2) :: eigval
END TYPE matrix2
Now the following matrix multiplication code would be very efficient compared to looping through the rank 1 array and performing each matrix multiplication using MATMUL
TYPE(matrix2), DIMENSION(100) :: A, B, C
A%c11 = B%c11*C%c11 + B%c12*C%c21
A%c21 = B%c21*C%c11 + B%c22*C%c21
Alternatively, if the compiler was able to take advantage of the parallel components in an ELEMENTAL procedure, it would be a good idea to write a function to do this
TYPE(matrix2), INTENT(IN) :: B, C
TYPE(matrix2) :: A
A%c11 = B%c11*C%c11 + B%c12*C%c21
A%c21 = B%c21*C%c11 + B%c22*C%c21
If also non-scalar components are treated in the same way a more general matrix type that can take advantage of parallel component storage could easily be made:
TYPE :: matrix(n)
  REAL, DIMENSION(n) :: eigval
  PROCEDURE, PRIVATE :: matrix_mult
  GENERIC, OPERATOR(*) :: matrix_mult
END TYPE matrix
CLASS(matrix(B%n)), INTENT(IN) :: B, C
TYPE(matrix(B%n)) :: A
A%c = MATMUL(B%c,C%c)
END FUNCTION matrix_mult


Implicit compatibility inheritance for derived types

39.1 Proposal

An attribute to declare a component of a derived type to hold the “main data.” The derived type should (implicitly) inherit all applicable/compatible (and available) procedures and operators, both intrinsic and non-intrinsic, from this component. For a composite derived type, the remaining components could be considered, in a broad sense, as “meta data.”
This particular component will be referred to as the data-component from here on.

39.2 Rationale


39.3 Proposed syntax

39.3.1 Attribute name

39.3.2 An example

TYPE [[,type-attribute-list] ::] type-name [(type-parameter-name-list)]
  type-name, DATA :: component-declaration-list
END TYPE [type-name]

39.4 Examples of use

TYPE :: sqmat(n)
  REAL, DIMENSION(n,n), DATA :: mat
  REAL, DIMENSION(n) :: eigvals
  TYPE(vec(n)), DIMENSION(n) :: eigvecs
END TYPE sqmat
All intrinsic array procedures and operators, and in addition all available non-intrinsic with argument(s) compatible with the mat component, will be applicable to an instance of the sqmat type. One might of course define type-bound procedures in addition or as substitutes for one or more of the intrinsic ones as usual.
TYPE(sqmat(3)) :: sqmat3
REAL, DIMENSION(3,3) :: a3by3array
sqmat3 = a3by3array*sqmat3
sqmat3 = SIN(sqmat3)
sqmat3%mat is first multiplied (in the standard element-wise manner) with a3by3array, and the resulting 3-by-3 array is assigned back to sqmat3%mat. The result is the same as if the mat component would be explicitly specified each time sqmat3 is used. Then the intrinsic ELEMENTAL function SIN is applied to all the elements of sqmat3%mat which is then assign back to the same array. Furthermore, the following two statements are equivalent and they will both print a scalar which is the sum of all the elements of sqmat3%mat
PRINT *, SUM(sqmat3)
PRINT *, SUM(sqmat3%mat)


Implicit compatibility inheritance for arrays of derived types with a data-component

40.1 Proposal

As scalar–array and array–array compatibility/conformity works to ease the use of and empower intrinsic arrays; the same mechanisms should pertain to arrays of a derived types with a data-component (cf. section 39).

40.2 Rationale

40.3 Examples

see section 39.4 for the definition of sqmat. First we want to take sine of all the elements in the mat component of sqmat:
TYPE(sqmat(3)), DIMENSION(10) :: sqmat3_a1, sqmat3_a2, sqmat3_a3
sqmat3_a1 = SIN(sqmat3_a1)
This would normally not be valid code since the intrinsic elemental function SIN is not defined for the type sqmat, and neither would SIN(sqmat3_a1%mat)help anything since only scalar components may be referenced in that way when the encompassing structure is an array. With the proposed semantics though, this would be allowed syntax, and the result would be that SIN is applied to all 3x3=9 elements of each of the 10 mat data-components and then assigned back to their respective mat components. To achieve the equivalent behavior with f0x would require a DO loop over the the 10 sqmat elements of sqmat3_a1.
REAL, DIMENSION(3,3) :: a3by3array
sqmat3_a2 = sqmat3_a1*a3by3array
Here each of the 10 data-components in the array sqmat3_a1 is multiplied with a3by3array, which would be very useful if, say, each sqmat element is a rotation matrix and they are all to be incremented by a common additional rotation (represented by the matrix a3by3array). This behavior is not possible to obtain with an ELEMENTAL multiplication “operator procedure,” since it would have to accept an array as one of the arguments.
sqmat3_a3 = sqmat3_a1*sqmat3_a2
Now each of the 10 sqmat3_a1%mat is multiplied with the corresponding 10 sqmat3_a2%mat. The resulting 10 3-by-3 arrays are assigned to the corresponding mat components in sqmat3_a3, while any meta data in the latter is unaffected (to include these in the a defined multiplication operation one would have to write an elemental procedure for the sqmat type). The following statement prints a rank 1 array with extent 10 containing the sums of the 10 data-components
PRINT *, SUM(sqmat3_a1)

40.3.1 Comments to the examples


40.4.1 Example

The case: A derived type with an array data-component of a numeric type. The applicability of an operation will be based on whether the array SHAPEs are identical.

40.4.2 On implementation

Generalized, typed enumerators

Here the term set is used for both the notion of an ordinary set, i.e. a collection of unique values, and for the notion of a multiset, which may contain repeated/duplicate values.

41.1 Proposal

A generalization of the present Fortran ENUM type that works as a, possibly named, homogeneous collection of specific scalars of any type, is proposed. The ENUM type will be referred to as an enumerator or the set, and the “members” as the (enumerator) members.

41.2 Rationale

41.3 Proposed syntaxes

41.3.1 Definition

ENUM[(ordinal-triplet)] [,enum-attr-list] [:: enum-name]
  ENUMERATOR [::] enum-member-list
  [ENUMERATOR [::] enum-member-list]
END ENUM [enum-name]
where ordinal-triplet is the “standard Fortran triplet” giving the ordinal numbers of each member of the enumerator, in the sequence that they are specified in the block. The ordinal numbers works in much the same way as indices, with the important difference that they can be strided to allow for more flexibility, especially if enumerators are extended as described below. Another, hopefully obvious difference, is that the enumerator members need not be access through enum-name(ordinal-number) as they are named; but they could be accessed also in that way, again to allow for flexibility. If no triplet is provided a default numbering scheme is used, with lower bound of 0 or 1 (to be decided) and a stride of 1. For an unnamed enumerator the ordinal-triplet is only useful for INTEGERs without the BIND(C) attribute, as discussed below. An enum-attr is one of the following where access-spec is either PRIVATE or PUBLIC and controls availability of the enumerator.
A type-spec is an ordinary type specifier, possibly with type parameters, or TYPE(NONE) (which makes the enumerator ”purely symbolic”). If no type-spec is provided, nor is the BIND(C)attribute present, INTEGER is implicitly assumed and an optional type parameter in parentheses is allowed “by itself,” as if the INTEGER specifier actually was present. In this case the comma may also be omitted as long as an ordinal-triplet is not provided and a keyword is used (if a keyword was not used it would have been interpreted as a triplet). If the type is any other than TYPE(NONE) or INTEGER the enum-member-list must contain an initialization expression for each member. In the case of TYPE(NONE) the enumerator members may not take any value, and, hence, an initialization expression is not allowed. For INTEGER the values will equal the ordinal numbers in lack of an initialization expression, and therefore may be strided if an ordinal-triplet is supplied. This behavior may be abandoned by supplying the BIND(C) attribute, in which case the values are chosen according to the F03 standard, and no type parameters are allowed for INTEGER. If BIND(C) is given alone, an ordinal-triplet is disallowed and the rules regarding the member values (of INTEGER type) and KIND are the same as for the F03 ENUM “type.”
The EXTENDS(parent-enum-name-list) attribute, which prohibits any type-spec, gives the possibility to extend the number of members (with the same type-spec as its parent), and the parent enumerator(s) will become a subset of the child enumerator. The form of parent-enum-name-list is
parent-enum-name[(ord-sub)] [,parent-enum-name[(ord-sub)]]
where ord-sub is any of the forms of an array section subscript, i.e. subscript, subscript-triplet/section-subscript or vector-subscript. Using ordinal subscripts makes it possible to create (possibly named) subsets of a named enumerator.
If EXTENDS is given with a single parent name, an enum-name is optional unless the parent is of TYPE(NONE) and can, if it is not specified, be used to make the enumerator members of the parent enumerator available as ordinary constants of the type that the member values are (i.e. not of ENUM type). If an enumerator member is available both as an ENUM type and as an intrinsic or derived type, which one should be used can always be determined by the context (as they can never be mixed). An enumerator with type TYPE(NONE) can only be extended by named enumerators as it have no analogous variable type.
If EXTENDS is given with a single parent name and no ordinal-triplet, the numbering will continue as if any additional enumerator members was following on the next lines in the parent ENUM definition block. If both ordinal-triplet is given, and none of the ordinal numbers coincide, the ordinal-triplet will only pertain to the new members (if any).
If EXTENDS is given with more than one parent name, all the names must be of enumerators with identical/compatible type, and the result will be an union of all the parents' members plus any additional members included. If none of the ordinal numbers of the parent members coincide they will be kept, but if new members are added the parent ordinal numbers must in addition be such that they make up a sequence that could have been specified by a single triplet. If so, the new members will get ordinal numbers following that “imaginary” triplet. If any of the aforementioned conditions are not true, and/or if an ordinal-triplet is specified, the ordinal numbers will be restarted with default numbering or using the specified triplet, respectively.
The access-spec-statement may be either PRIVATE or PUBLIC, and pertains only to the accessibility of the member values. PUBLIC is default. Comment Examples of definitions
ENUM (KIND=1) :: colors
  ENUMERATOR :: red,green,blue
Both the ordinal numbers and the member values will be {0, 1 and 2 | 1,2 and 3} (to be decided) of type INTEGER(1) for red, green and blue, respectively.
ENUM(2::2), INTEGER, BIND(C) :: colors
  ENUMERATOR :: red,green,blue
The ordinal numbers will be 2, 4 and 6, and the values, due to the presence of BIND(C), will be 0, 1 and 2.
ENUM(6), REAL(4), PRIVATE :: numbers
  ENUMERATOR :: pi=3.1415_4, e=2.7182_4
The ordinal numbers will be 6 and 7.
TYPE :: triplet
END TYPE triplet
ENUM, TYPE(triplet) :: rgb_colors
  ENUMERATOR :: red=triplet(255,0,0),green=triplet(0,255,0)
  ENUMERATOR :: blue=triplet(0,0,255)
ENUM(rgb_colors) :: car_color, train_color
car_color = red
train_color = rgb_colors(2) !=green
Using the ordinal number for declaring train_color would not be possible if a variable with the same name as the numerator (rgb_colors) had been declared.
ENUM, TYPE(triplet) :: cmyk_colors
  ENUMERATOR :: cyan=triplet(0,255,255), magenta=triplet(255,0,255)
  ENUMERATOR :: yellow=triplet(255,255,0)
ENUM(ord-triplet), EXTENDS(rgb_colors,cmyk_colors) :: more_colors
  ENUMERATOR :: brown=triplet(...), pink=triplet(...)

41.3.2 Type declarations for named enumerators

ENUM(enum-name) [[,attr-spec] ::] entity-declaration-list
This statement declares one or more entities that may be assigned, either in an initialization expression or through assignment, to members of the enumerator enum-name, and only those. Entities declared in this way, however, are always POINTERs to the assigned enumerator member, or at least behave as if they were, so by assignment it is implicitly meant pointer assignment. This ensures that entities defined using the ENUM type specifier do not change since the enumerator members themselves are constants, and, furthermore, it provides the (pointer) variable with all the intrinsic enumerator functions described below, such as access to the ordinal number. One could call these proper enumerator variables to distinguish them from the ones declared using the syntax below. access-spec is either PRIVATE or PUBLIC and is the only allowed attribute. If a DIMENSION attribute is provided, it refers to the entity being declared and not the target member, since these are always scalar, which is the same behavior as if the SCALAR attribute (described in section 37) was used.
A variable may also be given the value of an enumerator member using the syntax
TYPE(enum-name) [[,attr-spec] ::] entity-declaration-list
where attr-spec and entity-declaration-list follow the usual rules of any variable declaration of the same type as that of the enumerator enum-name. The only difference to using the enum-name instead of the type designator of the enumerator enum-name, is that in an initialization expression only members of enum-name are allowed on the rhs., and in general assignment statements members of enum-name are allowed be on the rhs. Even if the value of the enumerator members are PRIVATE to the scope in which the assignment takes place, the value is still assigned to the entity (or all elements of the entity if it is an array) as if an ASSIGNMENT routine was defined as an “enumerator-bound procedure.”

41.3.3 Intrinsic functions

The following intrinsic functions, accessible also using (pseudo-) component syntax, i.e. enum-member-name%func-name, should be available for variables declared with the ENUM specifier, as well as the enumerator members themselves: The name of an enumerator, enum-name, takes an integer argument itself and works like a function to return the enumerator member with the corresponding ordinal number: enum-name(ord). The following expression would return .TRUE.: enum-name(enum-member-name%ord) .EQ. enum-member-name. In addition the following functions are defined for the enum-name: The behavior when using READ, WRITE or PRINT statements with enumerators (i.e. when specifying an enum-name), enumerator members and variables declared with the ENUM specifier (i.e. proper enumerator variables) should be a different from the other intrinsic types. As an enumerator in it's simplest, and perhaps purest, form is just a symbolic designator that holds no other information, and this is possible through the TYPE(NONE) in the proposed framework. The most important aspect of an enumerator is then the knowledge that it is unique, and therefore it can be used to pass information in an indirect manner as a “symbolic flag.” The names of enumerator members often convey this abstract idea of uniqueness; and the notions of array indices and ordinal numbers likewise are of enumeration nature, with a subset of integers as members. Although, when using enumerators in programs it is often convenient to couple them with a value (which does not need to be unique), but this is never strictly necessary as the value, or even a set of values, could be obtained by other programming structures; and it does not change the nature of enumerators.
In this spirit it is proposed that when using I/O statements the “value” of the aforementioned types should be the member name, or the members' names, depending on the situation. To print the ordinal number or value these must be explicitly referenced with the functions listed above. With this behavior it is for example possible to reference a variable name directly through a READ statement instead of having to read in a number or character string and then programmatically choose the desired enumerator member. Examples of I/O
ENUM(rgb_colors) :: car_color = red
PRINT *, 'Present color:',car_color
WRITE(*,100), 'Available colors are:', rgb_colors
READ(*,*) car_color
This code block defines car_color as a (proper) enumerator variable, and initializes it to (point to) the enumerator member red. The first PRINT statement prints the character string
Present color: red
to OUTPUT_UNIT, i.e. not the value of type triplet that is bound to red. The WRITE statement prints all the member names of rgb_colors after the literal character string constant, as if rgb_colors was substituted with MEMBERS(rgb_colors). In the last statement an enumerator member name character string should be supplied through INPUT_UNIT, and this very behavior may simplify code writhing significantly when reading in data, as no checking of a numeric or character input is needed in order to determine the proper action.
One can possibly also accept either an index number or an ordinal number, where the latter is preferred due to their importance versus the index numbers, but then the ordinal numbers should also (automatically) be printed along with the member names in the WRITE statement. A possible output form could be
ordinal-number: enum-member-name
while member names without ordinal numbers could still be printed using MEMBERS(rgb_colors) as described above.

41.3.4 Type declarations for unnamed enumerators

Unnamed enumerators, obviously, cannot be referenced by any name, only enumerator members may be referenced. This is analogous to F03 ENUMERATORs, except for the possibility for the enumerator members to hold a value of any type.


Multiple derived type parents

42.1 Proposal

Allow a list of parent type names in an EXTENDS attribute specification.

42.2 Rationale

42.3 Proposed syntax

TYPE, EXTENDS(parent-type-name-list) :: type-name [(type-param-name-list)]

42.4 Comment

42.5 Example

TYPE :: typ1
  REAL :: r
TYPE :: typ2
  INTEGER :: i
TYPE, EXTENDS(typ1,typ2) :: typ3
  LOGICAL :: l
TYPE(typ3) :: comb = typ3(1.0,2,.TRUE.)

A data type for rational numbers

43.1 Proposal

Add a datatype for representing rational numbers accurately by two INTEGER numbers

43.2 Rationale

43.3 Proposed syntax

43.3.1 Data type name

43.3.2 Constructor operator

43.4 Proposed semantics

43.4.1 Sign

43.4.2 Common factors

43.4.3 Type conversions To RATIONAL From RATIONAL

43.5 Additional functionality: mixed representation

43.5.1 Proposal & rationale

43.5.2 Proposed semantics

New intrinsic data structures

The data structures below are proposed to complement arrays. The proposed structures can be realized by derived types (with the appropriate bound procedures) but as they represent basic structure types it would be a natural enrichment of the language to have built-in support for them. That would also likely make them more powerful than an user implementation, more user friendly as special structure types need not be made for each data type, and obviously portability would be better.

44.1 Lists and arrays of lists

44.1.1 Proposed syntaxes Declaration of scalar lists
type-spec, LIST, [attr-list] :: variable-declaration-list Declaration of array lists
type-spec, LIST(shape-spec), [attr-list] :: variable-declaration-list
where shape-spec must be a colon list if ALLOCATBLE is specified in the attr-list List constructors List qualification
This follows from the syntax proposed in section 24; i.e. one of the following
where the former should only be considered in the case that the proposal of section 18 is not sanctioned, for reasons of consistency. The latter will be used in the following. List qualification for arrays of lists Array qualification of arrays in a list Inquiry on lists Operations on lists

44.1.2 Example of a scalar list

Below an “ordinary” scalar list of REAL scalars is declared and some elements are
REAL, LIST :: lst
lst = {3.14, 2.71}
lst = lst%insert(1.73)
lst = lst // {REAL :: 0.577, 2}
lst = lst%insert({1.41,arr},4)

44.1.3 Example of a rank 2 array of lists

REAL, LIST(2,3), DIMENSION(:) :: list2d
CALL list2d[2,1]%trim({2,6:12:2})
list2d[2,2] = list2d[2,1]|{2:-1}[1:9:2]
where the trim procedure is realized as a SUBROUTINE working in-place on the list list2d[2,1], removing the list elements (which are rank1 arrays) with indices 2, 6, 8, 10 and 12 from the list. The list assigned to list2d[2,2] would consist of the array elements with indices 1, 3, 5, 7 and 9 of all the list elements of list2d[2,1] except for the first and last.
The list declared in the simple list declaration above would be similar in structure to
TYPE real_list1d
  TYPE(real_list1d), POINTER :: nxt => NULL()
  PROCEDURE :: idx => index_real_list1d
  GENERIC :: ASSIGNMENT(=) => alloc_elm_set_nxt
END TYPE real_list1d
TYPE(ptr_list1d), DIMENSION(2,3) :: dlist2d
In addition, if one desires to have a similar list where the elements are pointers to other data objects a different assignment procedure would have to be provided.

44.1.4 Additional proposals Additional semantics for lists
A list could be endowed with the additional semantic that the usage of a list would be equivalent to a comma-separated list in the source code. This is a natural semantic interpretation for lists and brings functionality that is impossible for arrays, and the previously proposed list features, such as array qualification of lists, would make this a very powerful feature. Some examples of how this could be utilized follows: where list-spec is a list name or a section of a list. Inhomogeneous lists
A list could be allowed to be declared as unlimited polymorphic, specifically by using CLASS(*) for type-spec in the list declaration, in order to facilitate inhomogeneous lists. As the implementation of a list should be using pointers, this is straight forward, and it brings the obvious requirement that each list element, if array valued, must homogeneous. To facilitate a set constructor for inhomogeneous lists it is further proposed that the following forms should be allowed: where class-spec is either a derived-type-spec or an asterisk. Conversion by (intrinsic) assignment
It should be possible to have a list with scalar valued elements on the lhs. in an assignment when the data object on the rhs. is an array of a conforming type. The list and array must have the same number of elements, i.e. the list length and the array size must be equal, and any reallocation on assignment must be suppressed (at least for arrays of rank higher than 1) for which an array constructor must be used (possibly with RESHAPE).
For an array of a derived type containing array valued components it is presently not allowed to reference an array section of the derived type array and a section of the array component “at the same time.” With the proposed intrinsic list structure it is natural that such a “nested section” be allowed, resulting in a list of the array valued components in the array element order of containing structure (i.e. the array of the derived type). In the case that the component is scalar valued the array returned can easily be cast into list form by using the set syntax list constructor, which provide a means to achieve consistent behavior for all “nested sections.”
The inverse operation could be defined to be the assignment of a list to a component of an array of a derived type, which is not strictly the inverse operation (which is impossible since it would imply the definition of a derived type on the fly), but serves the purpose. This functionality is to derived types the analogous to how an array constructor can be used (as proposed above) as a means to convert a list of scalars (including all intrinsic types) into an array.
These two latter semantical definitions provide a means to rearrange (e.g. sort) arrays of derived types by converting each component into a list (perhaps collect all the “component lists” in an array of lists), arrange for the desired ordering, and finally reassign the list back to the array. This would of course have the greatest potential (compared to using temporary variables) when significant rearrangements, which cannot be determined a priori, are needed. Examples using the additional proposals
REAL, DIMENSION(10,10,10) :: arr
INTEGER :: a(3), b(4), c(5)
  : !a, b and c are assigned values
lst = {/ a, b, c /}
IF ( ALL(a[lst] == a[a,b,c]) ) PRINT *, 'Ok'
This snippet would output “Ok” as the two array sections would be identical. Alternatively the list constructor {/ a, b, c /} could be provided directly, but that would not bring any advantage over the usual syntax unless it was additionally combined with an array qualification, say.
Below is an example of the declaration of inhomogeneous lists
CLASS(*), LIST :: list_of_scalars, list_of_arrays(:,:,:)
list_of_scalars = {3.5} !a default REAL
list_of_scalars = list_of_scalars%insert{7} !a default INTEGER
Next, using the following type definition and declaration
TYPE :: sqmat(n)
  REAL, DIMENSION(n,n), DATA :: mat
  REAL, DIMENSION(n) :: eigvals
  TYPE(vec(n)), DIMENSION(n) :: eigvecs
END TYPE sqmat
TYPE(sqmat(5)), DIMENSION(10) :: sqmats
the following “nested sections”
would result in a list of 10 REAL rank 1 arrays (of size 5), a list of 5 4-by-3 REAL rank 2 arrays, and list of 10 rank 1 arrays of type vec(5) containing the first 3 (out of 5) eigvecs of each sqmat, respectively. Furthermore, the following statement would produce a 10-by-5 REAL array
[/ sqmats%eigvals /]
utilizing the extended array constructor (cf. with section 20) and that a list is equivalent to a comma separated list. The last example demonstrate how move the eigvals arrays in the sqmats array by utilizing intrinsic list–array conversion
lst = sqmats%eigvals
lst = lst%cshift(3)
sqmats%eigvals = lst


44.2 Sets

44.2.1 Proposed syntaxes Declaration of non-limited sets
type-spec, SET(*) [, scal-attr-list] :: variable-declaration-list Declaration of limited sets
type-spec, SET(set-universe) [, scal-attr-list] :: variable-declaration-list Specification of tolerance for floating point representation comparisons
Could be implemented as the number of representable numbers (cf. with SPACING) between the two numbers being compared
real-or-cmplx, SET(*), TOL(init-expr) [, scal-attr-list] :: variable-declaration-list Operations on sets Additional operations on limited sets Examples
The set declared in the following statement
TYPE(dtype), DIMENSION(:), SET(*) :: rset
is a set of rank 1 dtype elements and the number of elements in the set is not limited (other than to the available memory), resulting in the need for a mechanism to keep track of the member elements, e.g. a hash table.
The declaration
INTEGER, SET({-2,-1,0,1,2}) :: iset1, iset2
declares a finite/limited set of scalar integer elements of which only numbers between -2 and 2 (inclusive) are allowed (the universe of the set). A “bit-vector” of minimum 5 bits may be used to keep track of the members of each set, providing a very efficient way of performing operations on the set.

44.2.2 Extension to multisets

A mechanism to keep track of multiple instances of an element could be available, effectively achieving the notion of multisets. This would just require a counter for each member element that was incremented when a value was appended to the set and a bound function, count, say, to retrieve the count of a member (for simplicity, the function could take a label, or a vector of such ones, as argument). The SET attribute could simply be replaced with one of MSET, MULSET or MULTISET to request such a mechanism to be initiated

44.2.3 Extension to inhomogeneous sets

By allowing CLASS(class-spec), where class-spec is either a derived-type-spec or an asterisk, in the declaration statement of a set it would be possible to have inhomogeneous sets. Uniqueness would then be assessed only among data objects of identical type since other types would trivially be different.


1Michael Metcalf, John Reid and Malcolm Cohen, Modern Fortran Explained, OUP Oxford, Mar 24, 2011
2 J. C. Adams et al., The Fortran 2003 Handbook: The Complete Syntax, Features and Procedures, Springer, 2009
3 Fortran Language Reference Manual, Volume 1 - S-3692-51, Chapter 4. Data Types, docs.cray.com
4 Espen Myklebust, Fortran Feature Proposals (– The complete set), 2013, PDF or XHTML