Hi all fortran gurus !
I would like to discuss the current methods to manage
templates in fortran, following the thread
http://groups.google.com/group/comp.lang.fortran/browse_thread/thread/f055f8=
70774d98a0/110fa05197d7b709?lnk=3Dgst&q=3Dtemplates+fortran#110fa05197d7b709=
which was very interesting, but showed no details on
how to pratically manage the source code.
This feature is very well-known by C++ developers as "templates".
One example of the problems solved by C++ templates is to
have a sorting source code which is able to manage for any
data type, including integers, reals, or even abstract data
types.
I currently know 3 ways of dealing with templates in fortran,
even if none of them is included in any fortran norm
(and none of them is detailed in a fortran book, to my knowledge) :
- pre-processing macros,
- clever use of the "include" statement,
- m4 macros.
Let's begin with the pre-processing macros.
Suppose that the file "sorting_template.f90" contains a template
sorting module, parametrized by the _QSORT_TYPE macro.
The following is an example of parametrized argument declaration :
subroutine qsort ( array, compare )
_QSORT_TYPE, dimension(:) :: array
Here "_QSORT_TYPE" may be an integer, a real or any fortran
derived type.
This name has been chosen because a fortran variable cannot
begin with an underscore so that no confusion can occur
between a preprocessing macro and a variable name.
Before using the template, one must instanciate it,
which is done with :
#define _QSORT_TYPE type(SORT_DATA)
#include "sorting_template.f90"
The "instanciation" is based, for example, on the following
SORT_DATA derived type, which may be defined in the
module "m_testsorting.f90" :
type SORT_DATA
integer key
integer index
end type SORT_DATA
Even if this derived type is quite simple, practical uses of this
method may include more complex data types.
The module "m_testsorting" has to be pre-processed before
being used. After pre-processing, the previous line has
been transformed to :
subroutine qsort ( array, compare )
type(SORT_DATA), dimension(:) :: array
With this method, generic source code templates can be
configured at will and allow to generate specific
sorting algorithms for whatever type of data.
This method can lead to more complex templates, with
no limit in the number of macros, that is, no limit
in the number of abstract data types in the template.
The main drawback is that the debugging process is not
possible interactively. This is because the source code
is generated at compile-time and the "template" does
not correspond to the post-processed one anymore.
One solution is to use manually the pre-processor to
generate the pre-processed template and to debug on that
later file.
Two other methods exist to manage to do generic programming
in fortran : the "include" statement and m4 macros.
The "include" fortran statement can be used so that the
target source code contains the definitions of an
abstract data type used in the template.
This method is used by Arjen Markus in the Flibs
library, for example in the linked list abstract
data structure :
http://flibs.sourceforge.net/linked_list.html
Here we suppose that the file "sorting_template.f90"
contains one sorting subroutine, which arguments
are defined like this :
subroutine qsort_array( array, compare )
type(SORT_DATA), dimension(:) :: array
The trick is to use the include fortran statement
to put that template source code into a context in
which the abstract data type is defined.
The following source code defines a module, the derived
type SORT_DATA and then include the template source code.
module m_testsorting
type SORT_DATA
integer key
integer index
end type SORT_DATA
contains
include "sorting_template.f90"
end module m_testsorting
The module m_testsorting is now providing the derived type
SORT_DATA and the methods to manage it, which are included
in the template. With a little more work, it is even possible
to make so that the final derived type has a name which
corresponds more to the one implemented by the abstraction,
as shown by Arjen Markus on the linkedlist example.
module MYDATA_MODULE
type MYDATA
character(len=3D20) :: string
end type MYDATA
end module
module MYDATA_LISTS
use MYDATA_MODULE, LIST_DATA =3D> MYDATA
include "linkedlist.f90"
end module MYDATA_LISTS
The main advantage of the "include" method is that
it uses only fortran statements so that the debugging
process is possible interactively. Moreover, it is very
elegant.
Another method is to use m4 macros to generate source code
at compile-time. Gnu m4 is an implementation of the traditional
Unix macro processor. This method is used by Toby White the
in the Fox library :
http://uszla.me.uk/space/software/FoX/
The template source code is defined in files which have the .m4.
extension and the corresponding source code is defined in the
=2EF90 file. The source code may be difficult to maintain, but the
method is extremely powerful, thanks to the m4 features.
For example, one can use a m4 "for" loop to generate
several subroutine based on one template subroutine.
But, as for the pre-processing method, the interactive
debugging of the .m4 templates is not possible :
instead, the processed .f90 generated files are debugged easily
and directly.
Are there other well-known methods ?
Is there a definitive drawback for one of these methods so
that another way should be chosen?
All comments will be appreciated.
Best regards,
Micha=EBl Baudin


|