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 :
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 :
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 :
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 :
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 :
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?
> 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 :
> 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 :
> 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 :
> 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 :
> 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 :
> 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.
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.
> 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 :
> 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 :
> 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 :
> 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 :
> 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 :
> 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.
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.
--->Would you consider these class facilities and unlimited polymorphic variables as "object-oriented?"
-- "Shopping for toilets isn't the most fascinating way to spend a Saturday afternoon. But it beats watching cable news."
> 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.
> --->Would you consider these class facilities and unlimited polymorphic > variables as "object-oriented?"
They can certainly be used in that way - for a suitable definition of "object-oriented". But the main point is that they give you the possibility to define interfaces that allow a wide range of actual types.
> > 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 :
> > 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 :
> > 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 :
> > 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 :
> > 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 :
> > 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- Tekst uit oorspronkelijk bericht niet weergeven -
> - Tekst uit oorspronkelijk bericht weergeven -
I must have a look again at Akin's book - the details have escaped me ;).
Note that templates in C++ are completely different beasts than what we are talking about here:
If you define a template A with one parameter T in C++ and then define in various pieces of your code the same instance, say a type A< int> in ten different source files, the compiler will have to create ten different copies of the actual object code that implements that particular type.
It is up to the linker to make sure that in the final executable program there is only one copy (or at least that there is no conflict between them).
So, in C++ the task is much more complicated than just generating specific source code from generic source code.
In Fortran we would have to generate the specific source code for each specific type. And as Michael indicates there are several methods for that. But in the end, for the compiler and linker it is just a larger set of ordinary code!
On 16 avr, 07:25, Damian <dam...@rouson.net> wrote:
> 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.
I have the book in my hands : "Object oriented programming via fortran 90/95" by Ed Akin. In fact, I was very enthousiast about the title, but the content was very disappointing to me. For me, the single article "Object-based programming in Fortran 90" by Gray and Roberts is much more interesting, because it gives the essence of OO : http://www.ccs.lanl.gov/CCS/CCS-4/pdf/obf90.pdf
About the problem of generic code, here is the only part where the subject is detailed, in chapter 3, p. 51 : "None of the OOP languages have all the features one might desire. For example, the useful concept of <<template>>, which is standard in C ++, is not in the F90 standard. Yet the author has found that a few dozen lines of F90 code will define a preprocessor that allows templates to be defined in F90 and expanded in line at compile time. [...]"
That is all : I did not find any paragraph showing how to practically implement templates in fortran, a subject which could have been at the core of the book with such a title. The second edition of "Fortran 90/95 explained" does not deal with that subject neither (but it may be done in the current edition, I don't know).
Comparing to the methods I allready know, Forpedo seems very interesting. The tool is easy to implement within a Makefile, as for m4 macros. The generic source code really looks like fortran source code, even with the macros like @T and <T>.
I did the following table to compare the methods - standard fortran : is the method in the fortran norm - debug : is the template source code easy to debug - features : does the method allow to manage complex templates (this is only my point of view)
Standard Debug Features Fortran ----------------------------------------------------------- include * ** * Pre-processing - * ** m4 - * **** forpedo - * *** fortran 2003 * ? ?
> On 16 avr, 07:25, Damian <dam...@rouson.net> wrote:
> > 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.
> I have the book in my hands : "Object oriented programming > via fortran 90/95" by Ed Akin. > In fact, I was very enthousiast about the title, but the content > was very disappointing to me. > For me, the single article "Object-based programming in Fortran 90" > by Gray and Roberts is much more interesting, because it gives > the essence of OO :http://www.ccs.lanl.gov/CCS/CCS-4/pdf/obf90.pdf
> About the problem of generic code, here is the only part where the > subject is detailed, in chapter 3, p. 51 : > "None of the OOP languages have all the features one might desire. > For example, the useful concept of <<template>>, which is standard in C > ++, > is not in the F90 standard. Yet the author has found that a few > dozen lines of F90 code will define a preprocessor that allows > templates > to be defined in F90 and expanded in line at compile time. [...]"
> That is all : I did not find any paragraph showing how to practically > implement templates in fortran, a subject which could have been at > the core of the book with such a title. > The second edition of "Fortran 90/95 explained" does not deal > with that subject neither (but it may be done in the current edition, > I don't know).
> Comparing to the methods I allready know, Forpedo seems very > interesting. > The tool is easy to implement within a Makefile, as for m4 macros. > The generic source code really looks like fortran source code, > even with the macros like @T and <T>.
> I did the following table to compare the methods > - standard fortran : is the method in the fortran norm > - debug : is the template source code easy to debug > - features : does the method allow to manage complex templates > (this is only my point of view)
Keep looking. There is a short passage with more details later in the book. Again, I'm pretty sure it's chapter 6, but I'll send an exact page later when I have my copy with me. The reason I found it similar to what you wrote is your use of the leading underscore, which you explained was because Fortran variables names cannot start with an underscore. In his case, he uses a trailing dollar sign ($) for a similar reason. Look for the string "Template$". The reason I'm so certain it's there is because I use his technique in my own code. I learned it from his book and haven't seen it anywhere else.
> > > 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 :
> > > 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 :
> > > 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 :
> > > 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 :
> > > 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 :
> > > 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- Tekst uit oorspronkelijk bericht niet weergeven -
> > - Tekst uit oorspronkelijk bericht weergeven -
> I must have a look again at Akin's book - the details > have escaped me ;).
> Note that templates in C++ are completely different > beasts than what we are talking about here:
> If you define a template A with one parameter T in C++ and > then define in various pieces of your code the same instance, > say a type A< int> in ten different source files, > the compiler will have to create ten different copies of > the actual object code that implements that particular > type.
> It is up to the linker to make sure that in the final > executable program there is only one copy (or at least that > there is no conflict between them).
> So, in C++ the task is much more complicated than just > generating specific source code from generic source code.
> In Fortran we would have to generate the specific source > code for each specific type. And as Michael indicates > there are several methods for that. But in the end, > for the compiler and linker it is just a larger set > of ordinary code!
You are right, I did not remember that part, but I read it. This is in chapter 6, p144, "Templates". My point of view is different from the one of the author about that problem and I hope that this chapter will be rewritten in the second edition, if ever.
Michaël
On 16 avr, 16:23, Damian <dam...@rouson.net> wrote:
> Keep looking. There is a short passage with more details later in the > book. Again, I'm pretty sure it's chapter 6, but I'll send an exact > page later when I have my copy with me. The reason I found it similar > to what you wrote is your use of the leading underscore, which you > explained was because Fortran variables names cannot start with an > underscore. In his case, he uses a trailing dollar sign ($) for a > similar reason. Look for the string "Template$". The reason I'm so > certain it's there is because I use his technique in my own code. I > learned it from his book and haven't seen it anywhere else.
On 15 Apr, 16:16, relaxmike <michael.bau...@gmail.com> wrote:
> Hi all fortran gurus !
> 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.
Hi,
From what I have experienced, after starting to program in Fortran after 15 years, is that there is very boring to write the same control logic all over the program, especially when you have to make a minor change and need to do the same update in many places. Not to metion the probability to introduce errors by doing so. I also find it boring to write the logic needed to be able to select a certain algorithm during program execution.
As I see it, parametrized derived types and CLASS(*) has the intention to let you do this, but I think that you have to include something more or extend the these constructs to really have something that helps.
One idea that I have: Would it not be possible to also parametrize the procedures?
Something like this
subroutine bbbbb(E,F,H,D) type,type :: A=(INTEGER,REAL),B=(TypeX,typeY),C character(10), length :: D=("AlgorithmA") type(A),allocateable :: E(:) class(B) :: B type(C) :: H . . . end
The compiler could then use the type of E and F, and the value of D, to select the specific subroutine to use, and I could use D to select the algorithm to use during program execution.
On Apr 16, 12:36 pm, gunnar <bjorkm...@gmail.com> wrote:
> On 15 Apr, 16:16, relaxmike <michael.bau...@gmail.com> wrote:
<snip> > From what I have experienced, after starting to program in Fortran > after 15 years, is that there is very boring to write the same control > logic all over the program, especially when you have to make a minor > change and need to do the same update in many places. Not to metion > the probability to introduce errors by doing so. I also find it boring > to write the logic needed to be able to select a certain algorithm > during program execution.
While I have experienced this code duplication "problem" on rare occasion, I find that I fail to see that it is a great programming concern. I don't oppose adding such capabilities to the language, but please make it a formal part of the language and not some add-on that will be poorly supported like a pre-processor that largely, probably, poorly duplicates functionality of a pre-existing native JCL or macro language or a more popular preprocessor for another language.
On 16 avr, 22:39, GaryScott <garylsc...@sbcglobal.net> wrote:
> While I have experienced this code duplication "problem" on rare > occasion, I find that I fail to see that it is a great programming > concern.
That really depends on what kind of problems you have to solve. "If you only have a hammer, everything you see is a nail."
Suppose you have to connect a fortran software with a Java platform and transfer data between the two with sockets. The subroutines which are used to manage the send/receive are complex and have to be able to manage all basic fortran data types : integer, real, character, and all possible arrays from rank 1 to rank 7. Let us count 3 * 7 = 21 subroutines to send data and 21 subroutines to receive data. But you also have to manage errors (21 more), etc... In short : the connection is not possible to do in fortran without fortran templates. The conclusion is : "Aaahh, that fortran language is crap, let's do it in C++ and the job will be done.". You think that this case cannot happen ? Yes it can happen, and it really happened 4 years ago in my last job. So my colleagues used pre-processing, which is a very good idea, and that worked.
In the case of Fox, that tool would simply not exist if fortran templates did not exist (based on m4 in that case).
The fact that "fortran is crap" or that "fortran templates are not a great concern" depends on what solutions you can put in front of the problems you have.
relaxmike wrote: > On 16 avr, 22:39, GaryScott <garylsc...@sbcglobal.net> wrote:
>>While I have experienced this code duplication "problem" on rare >>occasion, I find that I fail to see that it is a great programming >>concern.
> That really depends on what kind of problems you have to solve. > "If you only have a hammer, everything you see is a nail."
> Suppose you have to connect a fortran software > with a Java platform and transfer data between the two with > sockets. The subroutines which are used to manage the send/receive > are complex and have to be able to manage all basic > fortran data types : integer, real, character, and all possible > arrays from rank 1 to rank 7. Let us count 3 * 7 = 21 subroutines > to send data and 21 subroutines to receive data. But you also > have to manage errors (21 more), etc... > In short : the connection is not possible to do in fortran without > fortran templates. The conclusion is : "Aaahh, that fortran language > is crap, let's do it in C++ and the job will be done.".
I've been doing sockets without templates for 15 years. I'm not familiar enough with your above application comment on it though. I didn't imply there was no use for templates. I was suggesting that if we implement them, do it right, not through some half-a$$ preprocessor method. I oppose preprocessors, because whatever gets put in the standard will basically be inferior to tools I had on one or another operating system in the past and I'll always know how inferior it is as I try to force it to do things it wasn't designed for.
On 17 avr, 14:27, Gary Scott <garylsc...@sbcglobal.net> wrote:
> I oppose preprocessors, because whatever gets put in the > standard will basically be inferior to tools I had on one or another > operating system in the past and I'll always know how inferior it is as > I try to force it to do things it wasn't designed for.
You made a point here, because the pre-processing method is difficult to debug directly, except if you debug the pre-processed source code instead of the template one. This can be easily solved though, via makefile commands such as :
%.f90 : %.F90 $(FPP) $(FPPOPTS) $< -P $@
%.o : %.f90 $(FC) $(F90OPTS) -c $< -o $@
That is to say that the .F90 contains the template to pre-process. make start to compute the .f90 specific source code, depending on the template one. It is only the .f90 pre-processed source code which has to be compiled. This allows to debug interactively the specific source code, while maintaining only the template one. The "-P" option of the fortran preprocessor may allow to remove the lines introduced by the preprocessor in the preprocessed file which points to the line number in the original template.
Now that I have revealed all my very secret tricks (!!!), I don't see any main drawback to using pre-processing as a template method, except that the features implemented in many pre-processor are very poor, compared to what is possible in Python, m4 or Tcl for example.
Most compilers include a pre-processor inside the compiler itself, for example Intel Fortran, gfortran, g95, Sun, Ibm, etc... Even if the pre-processor is not included in your favorite compiler, or if you dislike the features that it provides, you can use an external one, for example the C pre-processor. If the C pre-processor is not available on the machine (which has a very low probability, but is possible), you can get the source of gcc and compile your own release.
In fact, the main reason why pre-processing macros are not used widely in fortran is for historical reasons, I suppose, and by the fact that many fortran developers are developing only in fortran, with high-level skills in science, most of the time, and, most of the time, low-level skills in software : there are many, many exceptions to this general fact, and these exceptions are the core of this forum. Put a C developer in front of a fortran source, and he will introduce a new pre-processing macro every 3 minutes...
What I am curious is at the fortran 2003 features which allows to do this. I think I'm going to read the standard again.
relaxmike <michael.bau...@gmail.com> wrote: > Suppose you have to connect a fortran software > with a Java platform and transfer data between the two with > sockets. The subroutines which are used to manage the send/receive > are complex and have to be able to manage all basic > fortran data types : integer, real, character, and all possible > arrays from rank 1 to rank 7. Let us count 3 * 7 = 21 subroutines > to send data and 21 subroutines to receive data. But you also > have to manage errors (21 more), etc... > In short : the connection is not possible to do in fortran without > fortran templates.
I agree that something like templates can be useful in some situations. But note that, depending on details, the particular scenario described above can usually be handled better in other ways. Typically, all you need is an equivalent of a C void pointer, along with the data size. Then you can do it all in a single procedure, with no need for templates. I've done this exact thing for a long time, as I also have Fortran code that passes data via sockets. So have other people. This one is done a lot.
You end up with a single procedure, rather than the multiplicity of procedures that the template approach involves. The template approach makes it more practical to create that multiplicity of procedures, but they still do end up having to get created.
In Fortran 90/95, you have to use tricks that aren't technically standard conforming, but still have decent portability in practice, in order to do the needed "type cheating". In Fortran 2003, you can use either the C interop features or the unlimitted polymorphic feature to make such code standard conforming.
-- Richard Maine | Good judgement comes from experience; email: last name at domain . net | experience comes from bad judgement. domain: summertriangle | -- Mark Twain
On 17 avr, 18:29, nos...@see.signature (Richard Maine) wrote:
> I agree that something like templates can be useful in some situations. > But note that, depending on details, the particular scenario described > above can usually be handled better in other ways. Typically, all you > need is an equivalent of a C void pointer, along with the data size. > Then you can do it all in a single procedure, with no need for > templates. I've done this exact thing for a long time, as I also have > Fortran code that passes data via sockets. So have other people. This > one is done a lot.
> You end up with a single procedure, rather than the multiplicity of > procedures that the template approach involves. The template approach > makes it more practical to create that multiplicity of procedures, but > they still do end up having to get created.
I don't understand how to implement this way. What kind of fortran data type corresponds to a C void pointer ? Let's take a practical example or reading a data in a string. The following source code read a data in an internal file and returns the value read, depending on the type of variable. It is over-simplified to make the point shorter. It does not use fortran templates, but only standard fortran.
subroutine readfile_data_logical ( current_data_line , myvalue , status ) implicit none character ( len = 200 ) , intent(in) :: current_data_line logical , intent (out) :: myvalue integer, intent(out) :: status status = 0 read ( current_data_line , * , err = 100 , end = 100) myvalue return 100 continue status = 1 end subroutine readfile_data_logical
subroutine readfile_data_integer ( current_data_line , myvalue , status ) implicit none character ( len = 200 ) , intent(in) :: current_data_line integer , intent (out) :: myvalue integer, intent(out) :: status status = 0 read ( current_data_line , * , err = 100 , end = 100) myvalue return 100 continue status = 1 end subroutine readfile_data_integer
It is very important to factorise this small code, because the interface could be extended way beyond the current state, for example reading more complex data types :
interface readfile_data module procedure readfile_data_logical module procedure readfile_data_integer module procedure readfile_data_real module procedure readfile_data_double module procedure readfile_data_logical_array1 module procedure readfile_data_integer_array1 module procedure readfile_data_real_array1 module procedure readfile_data_double_array1 module procedure readfile_data_logical_array2 module procedure readfile_data_integer_array2 module procedure readfile_data_real_array2 module procedure readfile_data_double_array2 [etc... until the maximum rank size available in fortran is reached = 7] end interface readfile_data
with the following header for the readfile_data_double_array2 subroutine :
subroutine readfile_data_double_array2 ( current_data_line , myvalue , status ) implicit none character ( len = 200 ) , intent(in) :: current_data_line real(dp), dimension(:,:) , intent (out) :: myvalue integer, intent(out) :: status
Developing the code with standard fortran is near to impossible, although hiring a PhD with European funds to do this is allways possible... With fortran templates, it is really easy. Suppose that the file "readfile_data_template.F90" contains the following source code, parametrized with the "_DATATYPE" macro.
subroutine readfile_data__DATATYPE ( current_data_line , myvalue , status ) implicit none character ( len = 200 ) , intent(in) :: current_data_line _DATATYPE , intent (out) :: myvalue integer, intent(out) :: status status = 0 read ( current_data_line , * , err = 100 , end = 100) myvalue return 100 continue status = 1 end subroutine readfile_data_integer
The previous source code would be using the template like this :
And now, with only 6 lines of source code, extending it to manage for several data types, and arrays of all possible sizes is possible. The same problem would be even easier to manage with Forpedo, I suppose.
Now, how do you suggest to solve the problem with your method Richard ? What is the fortran type which corresponds to the C void pointer ?
program test2 use m_moduletest2 character (len=200) :: current_data_line integer :: myintvalue1 logical :: mylogicalvalue1 integer :: status current_data_line = "1" call readfile_data ( current_data_line , myintvalue1 , status ) write ( * , * ) "status:", status write ( * , * ) "Integer : ", myintvalue1 current_data_line = ".true." call readfile_data ( current_data_line , mylogicalvalue1 , status ) write ( * , * ) "status:", status write ( * , * ) "Logical : ", mylogicalvalue1 end program test2
I tried to use "include" only statements without pre-processing, and that lead to a source code which I am not proud of. But the "C void pointer" idea leads to the following source. The "void" idea is managed with a derived type containing all possible fortran basic data types. The "pointer" is the class name, a string containing "integer", or "logical", depending on the type to manage. This is the source code :
module m_moduletest4 type :: DATATYPE integer :: value_integer logical :: value_logical character ( len = 200 ) :: classname end type DATATYPE contains subroutine readfile_data ( current_data_line , classname , myvalue , status ) implicit none character ( len = * ) , intent(in) :: current_data_line character ( len = * ) , intent(in) :: classname type ( DATATYPE ) , intent(out) :: myvalue integer, intent(out) :: status status = 0 myvalue % classname = classname select case ( classname ) case ( "integer" ) read ( current_data_line , * , err = 100 , end = 100) myvalue % value_integer case ( "logical" ) read ( current_data_line , * , err = 100 , end = 100) myvalue % value_logical case default write(6,*) "Bad classname." end select return 100 continue status = 1 end subroutine readfile_data subroutine printdata ( myvalue ) implicit none type ( DATATYPE ) , intent(in) :: myvalue write ( * , * ) trim(myvalue % classname) , ":" select case ( myvalue % classname ) case ( "integer" ) write ( * , * ) myvalue % value_integer case ( "logical" ) write ( * , * ) myvalue % value_logical case default write(6,*) "Bad classname." end select end subroutine printdata end module m_moduletest4
program test4 use m_moduletest4 character (len=200) :: current_data_line type ( DATATYPE ) :: myvalue integer :: status current_data_line = "1" call readfile_data ( current_data_line , "integer", myvalue , status ) write ( * , * ) "status:", status call printdata ( myvalue ) current_data_line = ".true." call readfile_data ( current_data_line , "logical" , myvalue , status ) write ( * , * ) "status:", status call printdata ( myvalue ) end program test4
Of course, dealing with that implementation consumes a lot of memory, especially if we include arrays of integers, arrays of logicals, etc... To solve that, we can use fortran 90 pointers and allocate only the type under use. Since the abstract data type is more complex, it is now time for full OO.
module m_moduletest5 type :: DATATYPE integer, pointer :: value_integer => NULL() logical, pointer :: value_logical => NULL() end type DATATYPE contains subroutine data_newfromstring ( this , current_data_line , classname , status ) implicit none character ( len = * ) , intent(in) :: current_data_line character ( len = * ) , intent(in) :: classname type ( DATATYPE ) , intent(out) :: this integer, intent(out) :: status status = 0 select case ( classname ) case ( "integer" ) allocate ( this % value_integer ) read ( current_data_line , * , err = 100 , end = 100) this % value_integer case ( "logical" ) allocate ( this % value_logical ) read ( current_data_line , * , err = 100 , end = 100) this % value_logical case default write(6,*) "Bad classname." end select return 100 continue status = 1 end subroutine data_newfromstring subroutine data_print ( this ) implicit none type ( DATATYPE ) , intent(in) :: this if ( associated ( this % value_integer ) ) then write ( *, * ) "integer :" write ( * , * ) this % value_integer elseif ( associated ( this % value_logical ) ) then write ( *, * ) "logical :" write ( * , * ) this % value_logical endif end subroutine data_print subroutine data_free ( this ) implicit none type ( DATATYPE ) , intent(in) :: this if ( associated ( this % value_integer ) ) then deallocate ( this % value_integer ) elseif ( associated ( this % value_logical ) ) then deallocate ( this % value_logical ) endif end subroutine data_free
end module m_moduletest5
program test5 use m_moduletest5 character (len=200) :: current_data_line type ( DATATYPE ) :: myvalue integer :: status current_data_line = "1" call data_newfromstring ( myvalue , current_data_line , "integer", status ) write ( * , * ) "status:", status call data_print ( myvalue ) call data_free ( myvalue ) current_data_line = ".true." call data_newfromstring ( myvalue , current_data_line , "logical" , status ) write ( * , * ) "status:", status call data_print ( myvalue ) call data_free ( myvalue ) end program test5
I admit that the current code is still manageable, but have many limitations that the pre-processing version have not, including : - the memory is managed at hand, which can lead to memory leaks. This is easy to manage with only 2 basic types, but what if there are 21 ? - the abstract data type cannot handle user-defined derived-types. The pre-processing system allows to define whatever type you want to, without any complication in the client source code. This is not the case with the hand-crafted "pointer to everything" abstract data type. On the good side, the source code is very easy to debug and uses only standard fortran 90 statements.
Still the current "pointer to everything" is a heavy solution. What if we wand to define a "writetostring" method : another 21*3 block of source code. And what if we want to define an error system for the class : another 21*3 block of source code ! This is not practical.
relaxmike <michael.bau...@gmail.com> wrote: > What kind of fortran > data type corresponds to a C void pointer ?
Type(C_PTR) in the F2003 C interop stuff.
-- Richard Maine | Good judgement comes from experience; email: last name at domain . net | experience comes from bad judgement. domain: summertriangle | -- Mark Twain
> I still try to experiment the idea, so here is a sample > full demonstration of the pre-processing way. > Here is the file "test2_template.F90" : > subroutine _READFILE_DATA_NAME ( current_data_line , myvalue , > status ) > implicit none > character ( len = * ) , intent(in) :: current_data_line > _DATATYPE , intent (out) :: myvalue > integer, intent(out) :: status > status = 0 > read ( current_data_line , * , err = 100 , end = 100) myvalue > return > 100 continue > status = 1 > end subroutine _READFILE_DATA_NAME > And this is the test file :
write(* ,*) trim(myvalue%classname), ":" select case(myvalue%classname) case("integer") call C_F_POINTER(myvalue%value, pi4) write(* ,*) pi4 case("logical") call C_F_POINTER(myvalue%value, pL4) write(* ,*) pL4 case default write(6,*) "Bad classname." end select end subroutine printdata end module m_moduletest6
program test6 use m_moduletest6 character (len=200) :: current_data_line type(DATATYPE) :: myvalue integer :: status current_data_line = "1" call readfile_data(current_data_line, "integer", myvalue, status) write(*, *) "status:", status call printdata(myvalue) current_data_line = ".true." call readfile_data(current_data_line, "logical", myvalue, status) write(* ,*) "status:", status call printdata(myvalue) end program test6
C:\gfortran\clf\template_war>C:\gfortran\win64\bin\x86_64-pc-mingw32-gfortr an te st6.f90 -otest6
C:\gfortran\clf\template_war>test6 status: 0 integer: 1 status: 0 logical: T
> - the abstract data type cannot handle user-defined derived-types. > The pre-processing system allows to define whatever type you want to, > without any complication in the client source code. > This is not the case with the hand-crafted "pointer to everything" > abstract data type.
Not the case, see my examples above.
> But you may suggest another way ?
Naturally.
-- write(*,*) transfer((/17.392111325966148d0,6.5794487871554595D-85, & 6.0134700243160014d-154/),(/'x'/)); end
relaxmike <michael.bau...@gmail.com> writes: > 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.
You forgot "callbacks":
! Fortran 95 implementation of the quicksort algorithm. This ! subroutine does not directly touch the array it sorts; rather it ! relies on the two callbacks "compare" and "exchange" for that. Code ! inspired by R. Sedgewick, "Algorithms in C" and correspondence with ! Glen Herrmannsfeldt.
subroutine quicksort(n, compare, exchange) implicit none integer, intent(in) :: n ! the length of the implied array
! The compare function must return an integer that is ! greater than zero if element(i) > element(j) ! equal to zero if element(i) = element(j) ! less than zero if element(i) < element(j) interface integer function compare(i,j) integer, intent(in) :: i, j end function compare end interface
! The exchange subroutine exchanges the elements at locations i and j. interface subroutine exchange(i,j) integer, intent(in) :: i, j end subroutine exchange end interface
do while(pop(left, right)) if (left .ge. right) cycle pivot = partition(left, right) if (pivot .gt. (left+right)/2) then call push(left,pivot-1) call push(pivot+1,right) else call push(pivot+1,right) call push(left,pivot-1) end if end do return
contains
subroutine push(l, r) integer, intent(in) :: l, r
stack(1, sptr) = l stack(2, sptr) = r sptr = sptr + 1 end subroutine push
logical function pop(l, r) integer, intent(out) :: l, r
if (sptr .gt. 1) then sptr = sptr - 1 l = stack(1, sptr) r = stack(2, sptr) pop = .true. else pop = .false. end if end function pop
integer function partition(l,r) integer, intent(in) :: l, r integer :: i, j
i = l j = r - 1 do do while (compare(i,r) .lt. 0) i = i+1 end do do while (compare(j,r) .gt. 0) if (j .eq. l) exit j = j-1 end do if (i .ge. j) exit call exchange(i,j) end do call exchange(i,r) partition = i end function partition end subroutine quicksort
Chip
-- Charles M. "Chip" Coldwell "Turn on, log in, tune out" GPG Key ID: 852E052F GPG Key Fingerprint: 77E5 2B51 4907 F08A 7E92 DE80 AFA9 9A8F 852E 052F
I must say that the method based on implicit statements is very clever, and, based only on fortran statements, allows to minimize the code duplication. But is it possible to declare something like this :
module data_mod type MYDATA character(len=20) :: string end type MYDATA implicit type(MYDATA) (Q) include 'test3_template.i90' end module data_mod
I don't think so, which shows that the method cannot be extended to abstract data types. But funny though.
The method based on "ISO_C_BINDING, only: C_PTR, C_LOC, C_F_POINTER" is interesting but leads to code duplication. If I where to use "ISO_C_BINDING", I think that I would use the C++ templates, and only define in fortran the interface to the C++ source code.
All in all, it would be much more simpler if the fortran language include a "template" feature in the core, which may be done, in 2043, may be...