From: relaxmike on
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/f055f870774d98a0/110fa05197d7b709?lnk=gst&q=templates+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=20) :: string
end type MYDATA
end module
module MYDATA_LISTS
use MYDATA_MODULE, LIST_DATA => 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
.F90 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ël Baudin

From: Arjen Markus on
On 15 apr, 16:16, relaxmike <michael.bau...(a)gmail.com> wrote:
> 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...
>
> 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=20) :: string
> end type MYDATA
> end module
> module MYDATA_LISTS
>     use MYDATA_MODULE, LIST_DATA => 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
> .F90 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ël Baudin

(One remark: part of the code you refer to was written
by Joe Krahn)

In Fortran 2003 you can use the class facilities and unlimited
polymorphic variables to solve these problems, but material
showing how to do that is limited so far.

Regards,

Arjen

From: Bil Kleb on
relaxmike wrote:
> Hi all fortran gurus !

Hi.

> Are there other well-known methods ?

Apparently not well-known, but there is:

http://www.macanics.net/forpedo/

Regards,
--
Bil Kleb
http://fun3d.larc.nasa.gov
From: Terence on
I wrote a commercial general sort/merge program (still in general
public use) that just reads in a text control file with :-
a) the input file name
b) the second input file name (for merges) or blank
c) the output file name
d) record length in bytes
e) then pretty much as many fields as you want, coded as
type,bytestart,bytelength,A/D [,and repeat]

You can also request a tag sort, where the file byte offeset addresses
of the sorted records are left in the output file (for cases where you
don't have twice the original data size available).

Of course it can't deal with arbitary fields beyond the expected
strings, integers, reals and T/F, nor does it sort variable length
records (but could easily changed to do so, nor does it cater for non-
MS byte order and FP formatting), but I see no need for the formal
route suggested.

I always prefer simple and practical.
From: Damian on
On Apr 15, 7:16 am, relaxmike <michael.bau...(a)gmail.com> wrote:
> 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...
>
> 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=20) :: string
> end type MYDATA
> end module
> module MYDATA_LISTS
> use MYDATA_MODULE, LIST_DATA => 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
> .F90 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ël Baudin

At least one text describes an approach equivalent to your pre-
processing approach: Object-Oriented Programming via Fortran 90/95 by
Ed Akin, Cambridge University Press, 2003. I don't have my copy at
hand but I'm pretty sure it's in Chapter 6.

Also, FWIW, some would argue that Fortran 2003 supports at least some
form of generic programming via parametrized derived types (definitely
not the same capability as templates but generic programming
nonetheless) and then there is the class(*) to which Arjen alludes.

Damian