|
From: relaxmike on 15 Apr 2008 10:16 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 15 Apr 2008 10:30 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 15 Apr 2008 12:33 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 15 Apr 2008 19:46 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 16 Apr 2008 01:25
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 |