Dr. Dobb's Journal February 2002
The next revision of the Fortran Standard, informally called "Fortran 2000," has passed beyond the stage of technical development, and NCITS J3 (http://www.j3-fortran.org/), the primary Fortran development committee, is in the process of integrating changes to the Fortran 95 Standard. In other words, features are no longer being added only document editing and the formal ISO processing remain for the new standard to be published. The expectation is that J3 will present its draft to WG5 (the ISO Fortran committee) in the summer of 2002. The WG5 process includes a public comment period before WG5 votes on the draft. If approved, WG5 will forward the draft to SC22 (the ISO programming languages committee) for approval, and (assuming all goes well) the standard will be formally published by ISO before the end of 2004.
Following the pattern of the last few releases of the Fortran Standard, Fortran 2000 is a big change just as Fortran 90 was a big change from Fortran 77. (Fortran 95, on the other hand, was a small change from Fortran 90. The committee's intention is to alternate big and small changes.) In this article, I describe the major features of Fortan 2000, based on the 01-007r2 draft. For more information, see http://www.j3-fortran.org/.
Fortran 2000's major new features include enhanced derived types, support for object-oriented programming, procedure variables, enhancements to the input/output features, full support of IEEE floating point (where supported by the hardware) including rounding during formatted input/output, interoperability with C external data and functions, and a few other features and previ- ously processor-dependent features.
Fortran 2000 supports a number of new features relating to derived types. Fortran has had user-defined derived types and the kind system for choosing types since Fortran 90. New with Fortran 2000 are parameterized derived types, default initialization values of derived type components, mixed component accessibility, public entities of private type, and finalizers.
Parameterized Derived Types. A parameterized derived type is a derived type definition where two varieties of parameters are left unspecified. These are kind parameters and nonkind parameters. Generic procedure resolution depends only on types used as actual arguments and the kind parameters (and also rank). When an object of a parameterized derived type is declared, values of the kind parameters are specified. Allocatable and pointer arrays have their extents deferred, otherwise, the nonkind parameters are specified when an object is declared. Nonkind parameters are used to define array extents and lengths of character entities.
In previous Fortran Standards, user-defined derived type components had to have their type and kind specified, array components had to have their extents specified (unless they were pointer arrays), and character components had to have their lengths specified. While this is sufficient for many purposes, it meant that two different variables of derived type that differed only in the kind of one or more components each had to have a separate derived type definition. Parameterized derived types means that only one derived type definition is needed. A kind parameter is passed to the type reference when a variable is declared, which specifies the kind of the component, the length of a character variable, or the bounds of an array dimension. Listing One illustrates parameterized derived types.
Mixed Accessibility of Derived Type Components. A derived type may have some of its components public while others are kept private. With Fortran 95, a derived type could have private components, but it was all or none.
Default Initialization of Derived Types. Derived types may specify default values for components of objects declared to have the derived type.
Public Entities of Private Type. You can provide a module containing a private derived type, which is unknown outside the module, and yet make public entities of that derived type. Of course, the module should also provide some procedures for manipulating the public entity. These procedures may be publicly available as procedures or operators. This technique lets module programmers exercise a maximum degree of information hiding with the derived type.
Type-Bound Procedures. Fortran 2000 implements type-bound procedures by adding a contains clause to derived type definitions. Procedure interfaces are declared within the type definition following the contains keyword. The actual procedure definition is specified following the contains statement of the module, program, or procedure containing the type definition. A dummy argument with the pass_obj attribute refers to the object to which the procedure is bound (the this argument). A type-bound procedure may be overridable, or nonoverridable in the case of an extended type.
Improved Finalizers. Finalizers (destructors) are type-bound procedures declared with the final keyword in the interface within the type definition. A final procedure executes when an object ceases to exist. It may be used to deallocate memory, free other resources, or ensure that other data structures are in a consistent state.
Fortran 2000 brings to Fortran inheritance, polymorphic pointers, dynamic type, and new executable constructs. These features let you implement object-oriented programs directly with high efficiency of the resultant executable.
Extensible Derived Types. Fortran 2000 implements inheritance with extensible derived types. A type may be declared to be extensible. Another type may then extend the first type. Fortran supports single inheritance; all types extended from a root type constitute a class. Of course, more than one type may extend a given extensible type; see Listing Two.
Polymorphism and Dynamic Type. Fortran 2000 implements polymorphism with polymorphic pointers that may point to an object of any type in a class. A polymorphic pointer may point to a variable of any type in the class. The type of the pointer may change within the class during execution. The select type construct allows choice of execution path depending on the current type of the pointer. The extends_type_of() and same_type_as() intrinsic procedures allow diagnosing the current type of a pointer.
The associate Executable Structure. Fortran 2000 implements a new associate executable structure, which lets complex names be specified by simple names. This can shorten variable names when types have nested components or complex array index expressions, enhancing readability. See Listing Three.
The select type Executable Structure. Fortran 2000 implements a new select type structure, which allows a choice of execution paths depending upon the current type of a dynamically typed variable. Listing Four illustrates this.
Fortran 2000 brings to Fortran allocatable components, the volatile attribute, explicit type specification in array constructors, declared intent for pointer arguments, specified lower bounds for pointers, and array pointers with different rank than their targets.
Allocatable Components of Derived Types. Fortran 2000 derived types may have allocatable components. Allocatable objects were originally intended to be objects (arrays are objects in Fortran) and to be used within the procedure where they were defined and perhaps passed as an argument to a procedure. Programmers have requested a more general capability, so derived type components may now have the allocatable attribute. This allows further optimizations that are not generally possible when using pointer components.
The volatile Attribute. Fortran 2000 implements a volatile attribute that warns the processor to always use the value of a datum found in memory. You can define an integer to be a hardware status word or define a derived type object to be an interface to some attached hardware, and volatile ensures that the compiler always uses the values in memory rather than keeping the object in register. Of course, this requires some help from the loader to place the object at the magic address.
The asynchronous Attribute. Fortran 2000 implements an asynchronous attribute, which warns the processor that a data item may be part of an asynchronous input/output transfer.
Explicit Type Specification in Array Constructors. Fortran 2000 allows the specification of a type and kind as part of an array constructor. This also means that a character length may be specified in a character array constructor.
Argument Intent for Pointer Arguments. Fortran 2000 allows specification of argument intent for pointer arguments. Argument intent of in, out, or inout may be specified for pointer dummy arguments, improving compile-time diagnostics and run-time performance.
Specified Lower Bounds of Pointer Extents. Fortran 2000 allows specification of lower bounds for pointer extents. This lets pointers have the same bounds as the target, or to hide a coordinate transformation via the pointer.
Pointer Rank Remapping. Fortran 2000 lets arrays have names of different rank. This may be useful when a mathematical object is most conveniently viewed as a two-dimensional array during part of a calculation and a one-dimensional array during other parts of the calculation.
Fortran 2000 describes user specification of user-defined derived type transfer operations, asynchronous transfer operations, the stream access method, user control of rounding, standard specified names for preconnected units, and access to error messages.
User-Specified Input/Output Operations for Derived Types. Fortran 2000 derived types may have user-specified transfer operations. You specify interfaces to programmer-defined procedures, which are called when the format string and/or the input/output list call for a transfer to a specified derived type. This lets you complete control of formatted or unformatted transfers of derived type objects.
The Stream Access Method. Fortran 2000 supports a stream access method whereby a file is considered a sequence of file storage units, recommended to be bytes, which are accessed in order without regard to a record structure. A file opened for stream access may be opened formatted or unformatted, which corresponds to the C language text or binary modes. Data may be transferred a single character or several characters at a time. If single characters are transferred, the result is similar to C's fgetc()/fputc() processing. It is intended that stream access files interoperate with files read or written by C programs, and the standard is written so vendors can use the same underlying library to implement both the C and Fortran support.
Asynchronous Input/Output Operations. Fortran 2000 supports asynchronous input/output transfers. Variables subject to asynchronous transfers are declared with the asynchronous attribute. The asynchronous transfer statement specifies a transfer identifier. The program can ensure that the transfer is complete by waiting at a wait statement specifying the same identifier.
Specified Control of Rounding. Fortran 2000 has new rounding format specifiers allowing control of rounding during conversion of real items between internal and character representation. Control is expressed by format descriptors in the format string, and thus may change from item to item.
Named Constants for stdin, stdout, stderr, and Access to Error Messages. Fortran 2000 has standard specified modules, called "intrinsic modules." The first of these is called iso_fortran_env, which contains named constants for the preconnected input (input_unit, aka stdin), output (output_unit, aka stdout), and error (error_unit, aka stderr) units. Fortran statements such as allocation and input/output statements, which may generate errors, now have access to the processor's error message.
Fortran 2000 standardizes the interoperability of Fortran and C entities. This allows use by Fortran programs of the many libraries available to C programmers and use by C programs of the many numerical libraries written in Fortran.
Fortran Kinds of C Types. Fortran 2000 provides an intrinsic module that defines named constant kind parameters for all C types. These constants are defined in the intrinsic module ISO_C, which the program should use to make them available. Fortran 2000 supports enumeration types, which are sized according to the rules of the target C compiler.
Binding Fortran Entities to C External Entities. Fortran 2000 provides a bind(C) attribute for binding a Fortran interface to a C function or binding a Fortran data item to a C external data item. A new value attribute of procedure arguments allows pass-by-value arguments to be used. Listing Five is a C interface as seen by the Fortran program.
Fortran 2000 has some additional features that are difficult to group under a broad heading other then miscellaneous.
Procedure Pointers and Abstract Interfaces. Fortran 2000 has procedure pointers and abstract interfaces that provide interfaces for the procedures indicated by procedure pointers. This lets the compiler check for correct usage of the procedure pointer at compile time.
Scoping Enhancements. Fortran 2000 allows the renaming of operators and supports the import statement in procedure interfaces. Since an interface block is its own scope, there needs to be a way to get definitions, especially derived type definitions, into the interface block. The import statement solves the problem.
ISO 60559 (IEEE 754) Support. Fortran 2000 standardizes access to ISO 60559 (IEEE 754) arithmetic, including control of rounding and exceptions. This is supplied by an intrinsic module specifying constants and procedures to detect and set modes. The program may check to see which modes are supported, what the current state of each mode is, and set each mode as needed.
Unicode Support. Fortran 2000 provides a consistent declaration for processors that support a character kind using ISO 10646. The character kind of ISO 10646, if available, is the return value of the intrinsic selected_char_kind('ISO_10646').
Command-Line and Environment Access and Error Messages. Fortran 2000 supports standardized access to a program's command line and its individual arguments (shell words) and to a program's environment variables. The command line may be retrieved all at once or word by word.
Enhanced Complex Constants. Fortran 2000 allows named real or integer constants in complex constants. For example, you might write complex :: minus_one = ( 0.0, pi), where pi is a previously defined constant.
min and max May Take Character Arguments. Fortran 2000 allows the max and min intrinsic procedures to take character arguments.
Some compilers already support parts of Fortran 2000, particularly the IEEE module and allocatable components of derived types. Hopefully, it won't be too long before fully standard compilers are available. I expect the interoperability with C features will be among the next wave of features to be supported.
It should come as no surprise that successors to Fortran 2000 are already in the works. While it's far too early to say exactly what the next standard will specify, the general thrust will be in the areas of increased support for object-oriented programming, better portability, ease of use, and (this is Fortran after all) better efficiency when using the modern features Fortran now supports. A TR is in the works to address the issues of compilation cascade involving modules and to make modules into a more sophisticated compilation unit. In short, J3 is alive and well, and the pipeline is full.
DDJ
! define parameterized derived type type :: matrix_t( k, d) integer, kind :: k ! k is a kind parameter real( kind= k), dimension( d, d) :: a ! d is a nonkind parameter end type matrix_t ! declare variable type( matrix_t( double_k, 100)) :: field ! field%a is ( 100, 100) of ! kind= double_k type( matrix_t( single_k, 50) :: potential ! potential%a is (50, 50) of ! kind= single_k
! define an extensible derived type type, extensible :: vector_3d real( kind= double_k), dimension( 3) :: point ! a point in three space end type matrix_t ! define type which extends vector_3d type, extends( vector_3d) :: vector_4d ! a point in 3 space real( kind= double_k) :: time ! at a time end type vector_4d
! Use a simple name in place of a complicated name associate( a => foo%bar( i, j, k)%element, b => sna%fu%last( i, j) ) ! use a, b end associate
! Choose execution based on type select type( p_ptr) type( foo_t) ! use a foo_t object type( bar_t) ! use a bar_t object end select type
! C prototype: void c_func( int i, double * a) interface, bind( c) :: c_func subroutine c_func( i, a) integer( kind= c_int), value :: i real( kind= c_double), dimension( 100) :: a end subroutine c_func end interface c_func ! and the call appears to be a normal call call c_func( i, a)