Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Generic types, anyone!

1,002 views
Skip to first unread message

FortranFan

unread,
Sep 25, 2015, 8:57:35 PM9/25/15
to
To achieve a greater support for generics in Fortran, what would it take for the brain-trust (members of standards committee, etc.) to offer their current thoughts on this matter, especially with regard to Fortran 20XY (the next update following Fortran 2015), and to get their views on the merit and demerit of suggestions like those offered below?

Consider a recent comment on this thread:

https://groups.google.com/forum/#!topic/comp.lang.fortran/wLA3mT63xtQ

where design options for vector types are being discussed and Jos Bergovoet brought up his code (http://bergervo.home.xs4all.nl/division_algebra.f90) using quaternions and asked, "Maybe someone here can advise me how to avoid the plethora of definitions (for instance all the argument type combinations for addition and subtraction). Perhaps by using generic types?" But as far I know, there is no good advice - there is no good solution to avoid the plethora of definitions one has to implement.

Separately I have mentioned a few times about the value I would find if I could have generic containers to work with trees, stacks, queues, etc.:
https://groups.google.com/forum/#!searchin/comp.lang.fortran/fortranfan$20generic$20java$20container/comp.lang.fortran/IPz-b_k3TJI/V2jx9l6y_p0J Again, there is no good solution other than the unlimited polymorphic option which comes with certain limitations.

Given above, I wonder whether introducing a new GENERIC :: TYPE => syntax can take care of the Fortran language aspects and then it will up to compiler implementations to figure out how to support it. To elaborate further, see below.

Say for quaternions case, one could have:
-- begin pseudo code --
module m

use, intrinsic :: iso_fortran_env :: wp => real64

implicit none

type, public :: quaternion
complex(kind=wp) :: c(2)
end type

type, public :: octonion
type(quater) :: c(2)
end type

type, public :: sedenion
type(octonion) :: c(2)
end type

!.. New syntax to define a generic type collection
generic, public :: type(t) => real(wp), complex(wp) !.. Not supported in the language,
generic, public :: type(u) => quaternion, octonion, sedenion ! but something along these lines will
! greatly extend the support of generics

!.. Above says t can be either real(wp) or complex(wp)
! and that u can be of quaternion, octonion, or sedenion type

generic, public :: operator(*) => mult_tu !.. I believe this is supported by Fortran 2015

contains

elemental function mult_tu(x, tion) result(rion)
!.. Single implementation takes care of several combinations of
! real/complex x and 3 types of *ions.

type(t), intent(in) :: x
type(u), intent(in) :: tion
type(u) :: rion

select type ( t )
type is ( real(wp) )
rion = u( x * tion%c )
type is ( complex(wp) )
rion = u([c * tion%c(1), tion%c(2) * c])
class default
!.. action elided
end select

end

end module m
-- end pseudo code --

And for a generic container, one could have:
-- begin pseudo code --
module m

use, intrinsic :: iso_fortran_env, only : i4 => int32, wp => real64
implicit none

private

type, public :: box(T) !.. borrows from existing PDT syntax

private

generic :: type(T) => integer(i4), real(wp) !.. defines T of be either a 4-byte integer or 8-byte real, etc.
!generic :: type(T) => type(*) !.. alternately, defines T to be of any type

type(T) :: m_t !.. type declaration of a component of generic type

contains
private
procedure, pass(this), public :: get => get_T
procedure, pass(this), public :: set => set_T
end type box

contains

subroutine set_T(this, val)

class(box(T)), intent(inout) :: this
type(T), intent(in) :: val

this%m_t = val

end subroutine

function get_T(this) result(retval)

class(box(T)), intent(in) :: this
!.. function result
type(T) :: retval

retval = this%m_T

end function get_T

end module m

program p

use m, only : box

implicit none

type(box(integer)) :: foo !.. a box holding default integers

call foo%set( 42 )

print *, foo%get()

end program p
-- end pseudo code --

I am not trying to imply the above is only way to extend generics or that the above would take care of all needs for generics - not in the least bit! Simply wondering how the thought process and analyses would go if the standards committee were to consider something like this. By the way, I often wonder how the PDT extension in the Fortran 2003 standard came about and what all got discussed while introducing that feature in the standard, and what the process that led to the language design that made it into the standard!

I am simply hoping the language would quickly build on the existing capabilities and syntax facilities (including those in the 2015 standard) to offer further improvements for generics. If suggestions like what I indicate above succeed in planting some thoughts and ideas in the minds of standard bearers and should they get motivated to build upon the concepts, I would find it most valuable, even if the final solution looks nothing like above. Ultimately all I am looking for are language capabilities to do the kinds of things expressed above.

Thoughts welcome,

Arjen Markus

unread,
Sep 28, 2015, 3:25:36 PM9/28/15
to
Op zaterdag 26 september 2015 02:57:35 UTC+2 schreef FortranFan:
>
....
>
> Thoughts welcome,

I had a brainwave and I tried to implement that using the current facilities. Unfortunately my compilers (Intel Fortran 2015 and gfortran 4.8 and 4.9) gave some errors, the Intel compiler complained about something I do not understand, gfortran (both 4.8 and 4.9) works fine on the code, but if I leave out a PRIVATE statement, the compiler crashes.

Anyway, I succeeded in doing what I wanted. I will write it up more carefully later, as it involves some juggling with USE and its clauses.

Regards,

Arjen

Arjen Markus

unread,
Sep 29, 2015, 2:49:27 AM9/29/15
to
The code below was inspired by the module Jos Bergervoet posted. It defines a "cascade" of types with a single, generically defined operation.

Some notes:
- The definition for quaternion is separate from the others, as I can not use the renaming feature with "complex".
- For this reason the generic definition of the derived type and the generic definition of the operation are in separate files.
- The code does two renames per derived type. Only the end result, the module algebraic_types should be USEd.
- The interface block is accumulative, no need to define the operator(+) interface in one block.

Remarks on compilers:
- gfortran had problems when I left out the PRIVATE statement for T2 (actually an ICE)
- Intel Fortran complained when I had two PRIVATE statements for T2. I do not understand that one.

I will report these issues on the respective platforms.

The code below consists of three files.

I have not looked at defining generic containers in this way yet, at least not in connection to this thread.

Regards,

Arjen

---
algebra_types.f90:
! algebra_types.f90 --
! Define a generic type
!
type T
type(T2) :: c(2)
end type T

---
algebra_generic.f90:
! algebra_generic.f90 --
! Define generic operation addition
!
interface operator(+)
module procedure add
end interface
private :: add

contains
elemental function add(op1,op2)
type(T), intent(in) :: op1, op2
type(T) :: add

add%c = op1%c + op2%c
end function add

---
! all_defs.f90 --
! Define a cascade of types
!
! quaternion_def.f90 --
! Define the basic type "quaternion"
!
module quaternion_def_basic
implicit none

type quaternion
complex :: c(2)
end type quaternion
end module quaternion_def_basic

module quaternion_def
use quaternion_def_basic, only: T => quaternion
include 'algebra_generic.f90'
end module quaternion_def

module octonion_def
use quaternion_def, T2 => T

implicit none

private :: T2

include 'algebra_types.f90'
include 'algebra_generic.f90'
end module octonion_def

module sedenion_def
use octonion_def, T2 => T

implicit none

!private :: T2

include 'algebra_types.f90'
include 'algebra_generic.f90'
end module sedenion_def

module algebraic_types
use quaternion_def, quaternion => T
use octonion_def, octonion => T
use sedenion_def, sedenion => T
end module algebraic_types

program test_algebraic
use algebraic_types

type(quaternion) :: q1, q2
type(octonion) :: o1, o2
type(sedenion) :: s1, s2

q1 = quaternion( [cmplx(1.0,0.0),cmplx(0.0,0.0)] )
q2 = quaternion( [cmplx(1.0,0.0),cmplx(0.0,1.0)] )

write(*,*) q1+q2

o1 = octonion( [q1, q1] )
o2 = octonion( [q2, q2] )

write(*,*) o1+o2

s1 = sedenion( [o1, o1] )
s2 = sedenion( [o2, o2] )

write(*,*) s1+s2
end program test_algebraic

Damian Rouson

unread,
Sep 29, 2015, 3:28:08 AM9/29/15
to
On Friday, September 25, 2015 at 5:57:35 PM UTC-7, FortranFan wrote:
> To achieve a greater support for generics in Fortran, what would it take for the brain-trust (members of standards committee, etc.) to offer their current thoughts on this matter, especially with regard to Fortran 20XY (the next update following Fortran 2015), and to get their views on the merit and demerit of suggestions like those offered below?

I see greater support for generic programing as imperative and I know at least one other committee member who would agree and at least a third who would probably join in support of a well-considered proposal. I also know of at least two additional people who would likely join the committee or at least participate considerably if the committee gives serious consideration to such a proposal. Even this count doesn't reach a majority, but it could reach a critical mass capable of swaying a majority.

I suspect generic programming would have come along sooner were it not for the proclivity of Fortran programmers to write stand-alone application codes. If more Fortran programmers were writing general-purpose libraries, in which they have no control over the types employed by the end application, I suspect the demand for generic programming would have long since reached whatever threshold of demand is required for inclusion in the language, but this is pure speculation and I'm open to the fact that others will disagree and might have substantial data and experience on which to base their disagreement.

One practical consideration is that the committee recently passed a straw ballot indicating that the _soonest_ new language features will be considered is 2017. In that regard, any proposals for generic programming facilities might well be premature unless more than a year is required to flesh out the ideas. The committee needs time currently to incorporate TS 18508 Additional Parallel in Fortran into the draft Fortran 2015 standard. The magnitude of this task along with other ongoing work (e.g. responding to standard interpretation requests, a.k.a. "interps") vis a vis the available human resources precludes the development and incorporation of new features within the next year or so.

With all that said, I'm glad for this post and I really, really, really hope there is a groundswell of support for some sort of generic progamming feature set in the next standard after Fortran 2015. It's the last best hope to stem the tide of defections to C++.

Damian

paul.rich...@gmail.com

unread,
Sep 29, 2015, 4:09:16 AM9/29/15
to
Hi Arjen,

If it is any consolation to you, the problem with the commented out PRIVATE statement has been fixed in gfortran-6.0.

I will check tonight to see if the problem has been fixed in 5.2.

Cheers

Paul

Arjen Markus

unread,
Sep 29, 2015, 4:26:15 AM9/29/15
to
Op dinsdag 29 september 2015 10:09:16 UTC+2 schreef paul.rich...@gmail.com:
Ah, I just provided a bug report on this :). Good to know that it has been fixed. Even though the message is clear enough and the fix in the code easy, ICEs are not what you want in a compiler (or any other piece of software).

Regards,

Arjen

glen herrmannsfeldt

unread,
Sep 29, 2015, 6:35:37 AM9/29/15
to
Damian Rouson <dam...@rouson.net> wrote:
> On Friday, September 25, 2015 at 5:57:35 PM UTC-7, FortranFan wrote:
>> To achieve a greater support for generics in Fortran, what would
>> it take for the brain-trust (members of standards committee, etc.)
>> to offer their current thoughts on this matter, especially with
>> regard to Fortran 20XY (the next update following Fortran 2015),
>> and to get their views on the merit and demerit of suggestions
>> like those offered below?

> I see greater support for generic programing as imperative
> and I know at least one other committee member who would agree
> and at least a third who would probably join in support of a
> well-considered proposal. I also know of at least two additional
> people who would likely join the committee or at least participate
> considerably if the committee gives serious consideration to such
> a proposal. Even this count doesn't reach a majority, but it
> could reach a critical mass capable of swaying a majority.

> I suspect generic programming would have come along sooner were
> it not for the proclivity of Fortran programmers to write
> stand-alone application codes.

(snip)

Depending on what you mean by generic programming, it isn't
especially easy the way Fortran is usually compiled.

One could, for example, compile each routine with floating point
variables and constants all in each of the available KINDs.
That is pretty much what people do now by hand, but it could
be automated.

If you do much more, the combinatorials will get you. Too many
different combinations.

-- glen

Arjen Markus

unread,
Sep 29, 2015, 7:03:45 AM9/29/15
to
Op dinsdag 29 september 2015 12:35:37 UTC+2 schreef glen herrmannsfeldt:

>
> Depending on what you mean by generic programming, it isn't
> especially easy the way Fortran is usually compiled.
>

Actually, that is a question that intrigues me. The current Fortran standard does facilitate quite a few things, but what are the features that are truly missing? Templates a la C++? But that can be emulated, even if not in a really elegant way.

Regards,

Arjen

Ian Chivers

unread,
Sep 29, 2015, 8:47:01 AM9/29/15
to
I think the major problem is the comparison with C++ and C#.
I did a course where the people had a mixed background of
Fortran, C++ and C#. There was an air of incredulity from the
C++ and C# people when we covered generic programming in Fortran.

Here is a generic quicksort in C++

\begin{verbatim}
template <class Type>
void swap(Type array[],int i, int j)
{
Type tmp=array[i];
array[i]=array[j];
array[j]=tmp;
}

template <class Type>
void quicksort( Type array[], int l, int r)
{
int i=l;
int j=r;
Type v=array[int((l+r)/2)];
for (;;)
{
while (array[i] < v) i=i+1;
while (v < array[j]) j=j-1;
if (i<=j)
{ swap(array,i,j); i=i+1 ; j=j-1; }
if (i>j) goto ended ;
}
ended: ;
if (l<j) quicksort(array,l,j);
if (i<r) quicksort(array,i,r);
}

template <class Type>
void print(Type array[],int size)
{
cout << " [ " ;
for (int ix=0;ix<size; ++ix)
cout << array[ix] << " ";
cout << "] \n";
}

#include <iostream>
using namespace std;
int main()
{
double da[] =
{1.9,8.2,3.7,6.4,5.5,1.8,9.2,3.6,7.4,5.5};
int ia[] = {1,10,2,9,3,8,4,7,6,5};
int size=sizeof(da)/sizeof(double);
cout << " Quicksort of double array is \n";
quicksort(da,0,size-1);
print(da,size);
size=sizeof(ia)/sizeof(int);
cout << " Quicksort of integer array is \n";
quicksort(ia,0,size-1);
print(ia,size);
return(0);
}
\end{verbatim}

Here is a generic quicksort in C#.

\begin{verbatim}
using System;
public static class generic
{

public static void
swap< Type > (Type[] array,int i, int j)
{
Type tmp=array[i];
array[i]=array[j];
array[j]=tmp;
}

public static void
quicksort< Type > ( Type[] array, int l, int r)
where Type : IComparable< Type >
{
int i=l;
int j=r;
Type v=array[(int)((l+r)/2)];
for (;;)
{
while (array[i].CompareTo( v) < 0 ) i=i+1;
while (v.CompareTo(array[j]) < 0) j=j-1;
if (i<=j)
{ swap(array,i,j); i=i+1 ; j=j-1; }
if (i>j) goto ended ;
}
ended: ;
if (l<j) quicksort(array,l,j);
if (i<r) quicksort(array,i,r);
}

public static void
print< Type > (Type[] array,int size)
{
int i;
int l;
l=array.Length;
for (i=0;i<l;i++)
Console.WriteLine(array[i]);
}

public static int Main()
{
double[] da =
{1.9,8.2,3.7,6.4,5.5,1.8,9.2,3.6,7.4,5.5};
int[] ia = {1,10,2,9,3,8,4,7,6,5};
int size;
size=da.Length;
Console.WriteLine("Original array");
print(da,size);
quicksort(da,0,size-1);
Console.WriteLine("Sorted array");
print(da,size);
size=ia.Length;
Console.WriteLine("Original array");
print(ia,size);
quicksort(ia,0,size-1);
Console.WriteLine("Sorted array");
print(ia,size);
return(0);
}

}
\end{verbatim}

edmondo.g...@gmail.com

unread,
Sep 29, 2015, 8:51:36 AM9/29/15
to
I think that with generic programming you are making a sort of contract between the generic class, procedure etc and the variable on which you are generalizing. This is solved by C++ a compile time. If for example a method for a given generic doesn't exist a lot of errors are printed, well because for example the operator "<" is not supported (as it should be for keys in the std::map in C++).

So what if a sort of interface for types are introduced. For example something like:

type, template :: u
contains
generic operator(<)
end type

And then a generic function could be constructed with that generic.

subroutine sort(a)
type(u) :: a(2)
if (a(2) < a(1)) ... !swap
end subroutine

I still think that the generic resolution should be done like C++ at the last time (I don't see how it can be coded efficiently otherwise), in the same line as happens when compiling with the -ipa option with ifort (that could be a big big issue for compiler writers.... perhaps)

Is it somewhere a list of use cases for generic programming in Fortran?
What we basically want to do with generic?
Is there a list of possible solutions with all drawbacks listed?
(So we don't propose always the same thing that is well known not to work)







Arjen Markus

unread,
Sep 29, 2015, 9:05:00 AM9/29/15
to
Op dinsdag 29 september 2015 14:51:36 UTC+2 schreef edmondo.g...@gmail.com:
Ian's example and your sketch seem to me to be well within the range of what Fortran can do right now. It just does not call it templates.

I will try to come up with a sample implementation.

Regards,

Arjen

edmondo.g...@gmail.com

unread,
Sep 29, 2015, 9:47:08 AM9/29/15
to
Well, yes, we may need more than that..
We may need:

1. A function or class may depend on more than one templated type T1, T2, etc.
2. Some implementation for some concrete types may be given explicitly. It may depend on having T1 concrete leaving T2 still a templated variable.
3. some methods or function should exist that have arguments of types T1, T2, T3, etc. all appearing in the same call.
4. It should solve the problem of general containers without the explosion of the number of subroutines.
5. others requirements...?

So the first point is how to express this in Fortran syntax without clashing with the existing one.
Second to keep it enough simple and powerful so that the compiler can easily do that without having to wait until 2030 before these feature are implemented (and just partially).
Third not to have the huge error message coming from C++ (even though most of the time related to not having used a const type when a const is required, at least according to my experience..)

Well I don't have any answer..






FortranFan

unread,
Sep 29, 2015, 12:24:11 PM9/29/15
to
On Tuesday, September 29, 2015 at 9:47:08 AM UTC-4, edmondo.g...@gmail.com wrote:

> ..
> We may need:
>
> 1. A function or class may depend on more than one templated type T1, T2, etc.
> 2. Some implementation for some concrete types may be given explicitly. It may depend on having T1 concrete leaving T2 still a templated variable.
> 3. some methods or function should exist that have arguments of types T1, T2, T3, etc. all appearing in the same call.
> 4. It should solve the problem of general containers without the explosion of the number of subroutines.
> 5. others requirements...?
>
> So the first point is how to express this in Fortran syntax without clashing with the existing one.
> Second to keep it enough simple and powerful so that the compiler can easily do that without having to wait until 2030 before these feature are implemented (and just partially).
> Third not to have the huge error message coming from C++ (even though most of the time related to not having used a const type when a const is required, at least according to my experience..)
>
> Well I don't have any answer..


So if the language introduces "GENERIC :: TYPE(..) => " syntax, does it not provide the framework to meet all the needs above? Re: compiler vendors, is this not simply "preprocessor" kind of work which may perhaps be simpler than the really difficult aspects they would have dealt with from Fortran 2003 (PDTs, OO, etc.) through 2015 standard (such as procedure improvements with GENERIC keyword)?


"1. A function or class may depend on more than one templated type T1, T2, etc" -
module m

..
generic :: type(T1) => real(sp), real(dp), integer(i4)
generic :: type(T2) => real(sp), real(dp), complex(sp), complex(dp)

contains

subroutine sort( .., foo, ..)

..
type(T), intent(inout) :: foo
..
end subroutine sort

subroutine someotherfunc( .., foo, bar, ..)
..
type(T1) :: foo
type(T2) :: bar
..
end subroutine someotherfunc

end module m

Then if another module wants to implement a concrete instance, the language might support something like this:

-- begin pseudo code --
module n

module m

procedure, type( real(wp) => T1 ) :: concretefunc => someotherfunc !.. provides a concrete implementation of someotherfunc where "complex(wp)" is substituted for generic type T1.

..

end module n
-- end pseudo code --

Similarly, if one wants to provide a concrete implementation of a generic derived type, the language might offer something like this:

-- begin pseudo code --
module m

..
type, public :: box(T) !.. borrows from existing PDT syntax

private

generic :: type(T) => integer(i4), real(wp) !.. defines T of be either a 4-byte integer or 8-byte real, etc.

type(T) :: m_t !.. type declaration of a component of generic type

contains
..
end type box

..
end module m

module n
..
use m
..
type, extends(box(real(wp)=>T)) :: r_box !.. provides a concrete implementation of box where generic type T is substituted with real(wp) to create a box of reals
..
end type r_box

end module n
-- end pseudo code --

Note the suggested changes above simply build on existing syntax for a) "GENERIC, .." procedure bindings, b) parameterized derived types, and c) "=>" token i.e., the => token is being applied in combination with GENERIC, PROCEDURE, EXTENDS keywords, etc. similar to the ways it gets in the language now. And note there is nothing much new or original here; the basic approach above is rather similar to what one finds in Java and in Microsoft's .NET languages, especially C#.

Can this not provide the mechanical framework to fill several of the gaps with generics in Fortran?

FortranFan

unread,
Sep 29, 2015, 2:02:52 PM9/29/15
to
On Tuesday, September 29, 2015 at 2:49:27 AM UTC-4, Arjen Markus wrote:

> The code below was inspired by the module Jos Bergervoet posted. It defines a "cascade" of types with a single, generically defined operation.
>
> Some notes:
> - The definition for quaternion is separate from the others, as I can not use the renaming feature with "complex".
> - For this reason the generic definition of the derived type and the generic definition of the operation are in separate files.
> - The code does two renames per derived type. Only the end result, the module algebraic_types should be USEd.
> ..
>
> I have not looked at defining generic containers in this way yet, at least not in connection to this thread.
>


@Arjen Markus,

Yes, there have been a couple of different approaches, one with "tricks" (such as renaming) with existing features and the second with preprocessors, where one can achieve such things.

My thoughts are that with some built-in syntax such as one using "GENERIC .. :: TYPE", one can not only make it easier for coders but also extent the concept to generic containers, as I show in the original post. That is what I am after.

Thanks much for your comments and attention,

FortranFan

unread,
Sep 29, 2015, 2:13:21 PM9/29/15
to
On Tuesday, September 29, 2015 at 8:51:36 AM UTC-4, edmondo.g...@gmail.com wrote:

> ..
>
> I still think that the generic resolution should be done like C++ at the last time (I don't see how it can be coded efficiently otherwise), ..

I disagree, I would prefer if Fortran follows the more "distilled" approach that other implementations like Java and Microsoft .NET with C# have followed with generics; the developers of these languages seem to have learnt from C++ and picked the better parts.


>
> Is it somewhere a list of use cases for generic programming in Fortran?
> What we basically want to do with generic?
> Is there a list of possible solutions with all drawbacks listed?
> (So we don't propose always the same thing that is well known not to work)

I don't know if there is a list somewhere. If one goes by examples, training materials, papers and discussions on Java and C#, generic procedures (like the sort procedure mentioned by Ian Chivers) and generic containers are the primary use cases. I will be most happy if Fortran were to focus on just these two use cases for the next standard revision following 2015, which ever year that may be!

FortranFan

unread,
Sep 29, 2015, 2:18:32 PM9/29/15
to
On Tuesday, September 29, 2015 at 8:47:01 AM UTC-4, Ian Chivers wrote:

> I think the major problem is the comparison with C++ and C#.
> I did a course where the people had a mixed background of
> Fortran, C++ and C#. There was an air of incredulity from the
> C++ and C# people when we covered generic programming in Fortran.
>

Can you please elaborate what the C++ and C# people were trying to imply by their "air of incredulity"? I think I know the feeling because I work with a lot of C# (and some C++, declining due to migration toward C#) folks, but would like to be sure!

Arjen Markus

unread,
Sep 29, 2015, 2:41:59 PM9/29/15
to
Op dinsdag 29 september 2015 20:02:52 UTC+2 schreef FortranFan:
One reason (for me at least) to juggle with the existing features to achieve this is that it gives me a better feeling for what we need. I also remember from publications that the C++ way of dealing with templates is pretty problematic: you can create something on the fly (as shown by Ian's code) but does that mean that each occurrence with the same type or types creates its own implementation or are they somehow unified?

By the way, the implementation I have ready (not quite as generic as I would like, but that will come), is more elegant by way of interface:

call quicksort( array )

suffices - no need to specify the upper and lower bounds.

Of course, that will not be seen as a plus by C++ /C# people ...

Regards,

Arjen

James Van Buskirk

unread,
Sep 29, 2015, 4:05:18 PM9/29/15
to
"Arjen Markus" wrote in message
news:32c6d487-363e-4ae0...@googlegroups.com...

> Ian's example and your sketch seem to me to be well within the range
> of what Fortran can do right now. It just does not call it templates.

> I will try to come up with a sample implementation.

One problem with Fortran syntax is that you can't rename
intrinsic types.

module mod1
type(integer), private :: nothing
public integer
end module mod1

module mod2
use mod1, only: t => integer
end module mod2

Will be rejected by the compiler, so if you don't
want just different KIND values for an intrinsic type
(see my GENERIC_BLAS example) or just derived types,
you have to implement via implicit typeing and that
has problems if you want to put an implicitly typed
member in a structure, for example.

Ian Harvey

unread,
Sep 29, 2015, 7:12:44 PM9/29/15
to
First noting that I might be misunderstanding the concept given it is
based only on example syntax, some comments below...

On 2015-09-26 10:57 AM, FortranFan wrote:
...
> Given above, I wonder whether introducing a new GENERIC :: TYPE => syntax can take care of the Fortran language aspects and then it will up to compiler implementations to figure out how to support it. To elaborate further, see below.
>
> Say for quaternions case, one could have:
> -- begin pseudo code --
> module m
>
> use, intrinsic :: iso_fortran_env :: wp => real64
>
> implicit none
>
> type, public :: quaternion
> complex(kind=wp) :: c(2)
> end type
>
> type, public :: octonion
> type(quater) :: c(2)
> end type
>
> type, public :: sedenion
> type(octonion) :: c(2)
> end type
>
> !.. New syntax to define a generic type collection
> generic, public :: type(t) => real(wp), complex(wp) !.. Not supported in the language,
> generic, public :: type(u) => quaternion, octonion, sedenion ! but something along these lines will
> ! greatly extend the support of generics

...

and from the next example...

> And for a generic container, one could have:
> -- begin pseudo code --
> module m
>
> use, intrinsic :: iso_fortran_env, only : i4 => int32, wp => real64
> implicit none
>
> private
>
> type, public :: box(T) !.. borrows from existing PDT syntax
>
> private
>
> generic :: type(T) => integer(i4), real(wp) !.. defines T of be either a 4-byte integer or 8-byte real, etc.
> !generic :: type(T) => type(*) !.. alternately, defines T to be of any type
>
> type(T) :: m_t !.. type declaration of a component of generic type


...

I think you want to very much avoid the need to specify the actual types
in the generic source code. A fundamental principle of this sort of
feature should be that you specify the minimum required characteristics
of the dummy type that the generic code supports (and some of those
characteristics may be things that you cannot express in the current
type definition syntax), but provision of the actual type (or actual
procedure, or actual constant, or whatever the parameterisation is based
around) happens later.

FortranFan

unread,
Sep 29, 2015, 8:59:35 PM9/29/15
to
On Tuesday, September 29, 2015 at 7:12:44 PM UTC-4, Ian Harvey wrote:

> ..
> I think you want to very much avoid the need to specify the actual types
> in the generic source code. A fundamental principle of this sort of
> feature should be that you specify the minimum required characteristics
> of the dummy type that the generic code supports (and some of those
> characteristics may be things that you cannot express in the current
> type definition syntax), but provision of the actual type (or actual
> procedure, or actual constant, or whatever the parameterisation is based
> around) happens later.

That might be true from a purist point-of-view for an OO language seeking rigorous support for generics.

But most of the recommended practices with practical implementations such as Java and Microsoft C# suggest including constraints as much as possible to inform the compiler what types go along with the method, interface, class, etc. e.g., "extends" keyword in Java and where in C#. So my thought has been why not setup Fortran generic types with constraints from the get-go. However, this needn't come in the way of further discussions and progress in ideas for generic types. If need be, the suggestion can be changed to a syntax such as

-- begin pseudo code --
module m

..
type, deferred :: T, U
..
contains

function mult( foo, bar ) result(prod)
type(T), intent(in) :: foo
type(U). intent(in) :: bar
..
end function mult

end module m

-- end code --

However my thinking based on my attempts to use parameterized types is that it is difficult to get all the "wiring" right because of limitations with the "KIND" parameter syntax. I wish there was some option for including some constraints in the syntax e.g.,

type :: t(k)
integer, kind :: k, only : sp, dp, c_double
..
end type t

It will be nice if that's not the case with generic types, that one can constrain the type of a particular set such as the *ions as one of the arguments in the first example in the original post.

Another thing with PDTs is it is rather difficult to make good use of the feature without include files. I would rather avoid include files. I hope any eventual support for generic types, should it get added to the language, won't necessitate the use of include files.

Ian Harvey

unread,
Sep 29, 2015, 11:18:45 PM9/29/15
to
On 2015-09-30 10:59 AM, FortranFan wrote:
> On Tuesday, September 29, 2015 at 7:12:44 PM UTC-4, Ian Harvey
> wrote:
>
>> .. I think you want to very much avoid the need to specify the
>> actual types in the generic source code. A fundamental principle
>> of this sort of feature should be that you specify the minimum
>> required characteristics of the dummy type that the generic code
>> supports (and some of those characteristics may be things that you
>> cannot express in the current type definition syntax), but
>> provision of the actual type (or actual procedure, or actual
>> constant, or whatever the parameterisation is based around) happens
>> later.
>
> That might be true from a purist point-of-view for an OO language
> seeking rigorous support for generics.
>
> But most of the recommended practices with practical implementations
> such as Java and Microsoft C# suggest including constraints as much
> as possible to inform the compiler what types go along with the
> method, interface, class, etc. e.g., "extends" keyword in Java and
> where in C#. So my thought has been why not setup Fortran generic
> types with constraints from the get-go. However, this needn't come
> in the way of further discussions and progress in ideas for generic
> types. If need be, the suggestion can be changed to a syntax such
> as

I think we are talking at cross purposes. Having the ability to
"specify the minimum required characteristics of the dummy type" - i.e.
constraints on the types that can be used - was one of my points.

The examples you quote from other languages are mechanisms to do just
that. But you don't specify the entire list of *actual* types - you
specify that "these procedures work with types that look like this".
Specification of the actual type occurs later, when the generic code is
actually used.

In your original example code, you defined three types, my
interpretation of your syntax was that the procedures were for working
with those three types (and perhaps types and specified kinds), and
those three types (and perhaps specified kinds) alone.

You had a type(*) specifier that appeared to stand for "some type to be
specified in future", but I did not see any explicit constraints on the
characteristics of that type. Implicit constraints would have existed
based on the generic code (e.g. objects of this unspecified type are
appearing in an expression on the left hand side of the multiplication
operator, therefore the unspecified type must support its objects being
used on the left hand side of the multiplication operator) but if
possible I think it best to avoid implicit statement of the requirements
on actual types, otherwise you end up with the "confusing error message"
situation that you can occasionally get with C++ templates.

> -- begin pseudo code -- module m
>
> .. type, deferred :: T, U .. contains
>
> function mult( foo, bar ) result(prod) type(T), intent(in) :: foo
> type(U). intent(in) :: bar .. end function mult
>
> end module m

I don't follow what you are trying to illustrate with that syntax.

Permit me to now confuse you by trying to illustrate some of my ideas
with syntax (and perhaps the odd comment). This is woefully incomplete
- I can shoot holes in it too.

Given their existing role in the language, I think modules represent the
natural unit for packaging together generic code (I have seen referenced
to parameterised modules in discussions around the feature set for
Fortran 2003, but I have not yet read any details about what
specifically was proposed). That lets you provide client code with
types, procedures and variables that are all based off the same
parameterisation. Contrast this with the approach taken with kind
parameterisation of types in Fortran 2003 - you can provide a
parameterised type, but providing a matching set of parameterised
procedures and variables requires things like INCLUDE hacks and the like.

(Given the existence of parameterised types in the language it may well
be useful to consider parameterisation at a level finer than a module -
perhaps at the procedure level.)


! The module m has two "dummy" parameters, identified as t and u.
MODULE m(t,u)
IMPLICIT NONE
PRIVATE

! This specifies that the identifier `t` is a type. When
! the generic module is used the name of a type must be
! associated with this parameter.
!
! Further, the "actual" type must match the interface
! of this type. I have tried to write things below such
! that an extension of `t` would always be a suitable match,
! but being an extension should not be a requirement.
!
! The abstract keyword is here to make it clear that this
! is not an actual type definition, it defines a template
! for the module parameter t. Perhaps this is unnecessary,
! perhaps it should be a different keyword, perhaps we want
! to separate specification of the characteristics of the type
! from the specification that the dummy parameter must match
! those characteristics.
TYPE, ABSTRACT :: t
! The actual type must have an integer component named `comp`.
INTEGER :: comp
CONTAINS
! The actual type must have a generic binding for OPERATOR(+).
GENERIC :: OPERATOR(+) => plus
! The actual type must have a specific binding called `plus`.
! That binding must match the given interface.
!
! The deferred keyword is here to maintain consistency with
! current syntax rules.
PROCEDURE(plus_intf), DEFERRED :: plus
END TYPE t

! This is the interface specification for the plus specific, and
! hence the OPERATOR(+) generic.
ABSTRACT INTERFACE
FUNCTION plus_intf(lhs, rhs)
IMPORT :: t
TYPE(t), INTENT(IN) :: lhs, rhs
TYPE(t) :: plus_intf
END FUNCTION plus_intf
END INTERFACE

! There is some nonsense in the above, in that all I want to
! do is state that operator (+) with the interface given by
! plus_intf must be accessible (I don't care about the
! name of the specific interface, perhaps the generic doesn't
! even need to be type bound).

! The identifier `u` is a value parameter of the module, and
! the associated actual value must be a default integer.
!
! In the current scope this identifier can be considered a
! named constant - as per KIND parameter of parameterised
! derived types in Fortran 2003. Perhaps we could allow
! for default values for value parameters that are unspecified
! at the point of use.
INTEGER, KIND :: u

! As you suggest, it would be nice (I think it a required
! feature) to be able to constrain the actual values of `u`
! in some way - combinations of value ranges and value lists.
!
! This aspect (and how it interacts with use of `u` as a
! kind parameter in the subprogram below) requires
! further thought.
! INTEGER, KIND, ONLY(INTEGER_KINDS) :: u
! INTEGER, KIND, ONLY(WHERE(x,x > 0)) :: u

! You might also want to parameterise on procedures.
! PROCEDURE(must_match_some_intf) :: u

! We can define module variables - these are common to all
! instances (all USE's) with the *same* parameters. Different
! parameters - different variables.
!
! (Being clear about when things are the same and when things
! are different may limit value parameters to being of type
! integer, otherwise you get into nonsense such as whether
! 0.0999999999999 is the same as 0.10000000000001.)
!
! In this case, the characteristics of the module variable
! depend on a value parameter.
INTEGER :: array(u)

! Specific procedure provided by this module. This procedure
! is not a generic interface, but it contains generic code.
PUBLIC :: Multiply
CONTAINS
FUNCTION Multiply(lhs, rhs) RESULT(r)
! Argument is of the dummy type.
TYPE(t), INTENT(IN) :: lhs
! Again, use of the value parameter, here as a kind
! parameter. In the absence of a constraint on the
! permitted values of `u` the requirement that the actual
! value of `u` be a valid integer kind value becomes
! implicit - I don't like this, so perhaps to permit use
! as a kind parameter a value parameter must be
! appropriately constrained.
INTEGER(u), INTENT(IN) :: rhs
! Function result is of the dummy type.
TYPE(t) :: r

INTEGER(u) :: i

! There are some common operations such as "construct with
! zero value" that you might want to specify as being
! available. In the absence of that, I just hope that
! client code never calls this with `rhs` less than one.
r = lhs
DO i = 2_u, rhs
! The dummy type `t` was constrained by the definition above
! to support OPERATOR(+) on two objects of `t`, returning
! a `t`, consequently this compiles.
r = r + lhs
! Implicitly in the above I am assuming that it is possible
! to assign one `t` object to another, but I don't think
! it is possible to prevent that in the current language.

! Because the dummy type definition did not specify
! any other generic identifiers, this would result in
! a diagnostic when attempting to compile this module.
! r = r - lhs

! We can do this... comp is a required component.
array(1) = array(1) + lhs%comp

! Referencing other components is a compile error.
! array(1) = array(1) + lhs%foo
END DO
END FUNCTION Multiple
END MODULE m


MODULE example_use
! Instantiate module m with the given actual parameters.
!
! There is a forward reference to the actual type definition
! here. Some thought is required as to whether this is
! problematic.
!
! The `array` module variable behind this instantiation
! is the same as the `array` module variable behind any
! other instantiation that uses the same type for t and same
! integer value for u. Because `type_a` is not a sequence or
! BIND(C) type, that means that it must be the `type_a` defined
! by this module (perhaps being used in a different module).
!
! How that would practically work with sequence types and
! BIND(C) types as actual types requires further thought!
!
! Actual value parameters must always be specified by
! constant expressions.
USE m(type_a, KIND(1))

! This would result in a compile error - you are trying to
! use associate two non-generic things with the same
! identifier (two instances of Multiply) and reference
! them in a scope. If you want to have two instances
! of the parameterised module active, you have to use
! the rename feature.
! USE m(type_b, KIND(1))

IMPLICIT NONE

! The actual type.
TYPE :: type_a
! We have our integer component, as required. Component
! order is not pertinent.
INTEGER :: comp
! We can have other components too...
REAL :: r
CONTAINS
! We have the required generic binding (and specific)
GENERIC :: OPERATOR(+) => plus
PROCEDURE :: plus => a_plus
! We can have other bindings too...
PROCEDURE :: a_multiply
END TYPE type_a
CONTAINS
FUNCTION a_plus(lhs, rhs)
TYPE(type_a), INTENT(IN) :: lhs, rhs
TYPE(type_a) :: a_plus
! ...
END FUNCTION a_plus

FUNCTION a_multiply(lhs, v)
TYPE(type_a), INTENT(IN) :: lhs
INTEGER, INTENT(IN) :: v
! Here is a reference to the specific procedure provided by
! the generic module, with that specific procedure instantiated
! for type a and the integer kind parameter value for default
! integer.
a_multiply = Multiply(lhs, v)
END FUNCTION a_multiply
END MODULE example_use

Arjen Markus

unread,
Sep 30, 2015, 3:47:56 AM9/30/15
to
Op dinsdag 29 september 2015 22:05:18 UTC+2 schreef James Van Buskirk:
> "Arjen Markus" wrote in message ...
Yes, I tried that renaming "trick" too and failed ;). Pity.

But I thought of another thing that has not been mentioned here as far as I have seen and that is that Fortran has a lot of flexibility to work with its main container type, arrays of various dimensions.

For instance: array operations, array sections and elemental routines. I know of nothing in C++ or C# or Java that comes close (C can't even begin to do something along those lines). I may be mistaken - my knowledge of Fortran far exceeds that of C++, C# and Java, but they are important aspects IMHO.

Regards,

Arjen

Wolfgang Kilian

unread,
Sep 30, 2015, 4:32:16 AM9/30/15
to
Parameterizing modules is natural, but I fear that this is not flexible
enough to be used much in real-life coding. IIRC, the original proposal
of parameterized modules required both a generic declaration module and
a concrete implementation module.

The most obvious use cases are generic algorithms (e.g. sorting) and
containers (e.g. list). Whatever the syntax is, the generic code might
reside in a module, library, etc., so you write

use list_features

but you don't want to explicitly declare an implementation module
list_features(foo_t), with all its implications about module dependency,
but simply proceed with

type(list(foo_t)) :: foo_list

where foo_t is some intrinsic or derived type that statisfies all
constraints on the type parameter as defined in list_features.

Stated otherwise, working with lists (for instance) should be as
straightforward as working with arrays. Working with sort (for
instance) should be as forward as calling transpose.

That said, there are uses for parameterized modules (aka functors),
namely if there is a whole subpackage (e.g., a 'model') with multiple
types, variables and procedures that depend on types or even whole
modules, and which can be selected by the client code at compile time.
But this is a bit clumsy if used for the simple purpose of defining a
list or sorting of something.

>> [snip code]

>> However my thinking based on my attempts to use parameterized types
>> is that it is difficult to get all the "wiring" right because of
>> limitations with the "KIND" parameter syntax. I wish there was some
>> option for including some constraints in the syntax e.g.,
>>
>> type :: t(k) integer, kind :: k, only : sp, dp, c_double .. end type
>> t
>>
>> It will be nice if that's not the case with generic types, that one
>> can constrain the type of a particular set such as the *ions as one
>> of the arguments in the first example in the original post.
>>
>> Another thing with PDTs is it is rather difficult to make good use of
>> the feature without include files. I would rather avoid include
>> files. I hope any eventual support for generic types, should it get
>> added to the language, won't necessitate the use of include files.
>>

Yes, of course. The current attempt at generic coding falls short of
being useful, therefore there is so little demand for its implementation.

-- Wolfgang


--
E-mail: firstnameini...@domain.de
Domain: yahoo

edmondo.g...@gmail.com

unread,
Sep 30, 2015, 4:51:18 AM9/30/15
to
Nice idea,
but let's assume we have a general container like a sorted list (like the std:set in C++).
And I want to have a sorted lists of sorted lists, using some operation to compare lists.

How can be achieved that?




Wolfgang Kilian

unread,
Sep 30, 2015, 5:13:58 AM9/30/15
to
The client code:

use set_tools
type (set (set (integer))) :: set_of_sets

The module set_tools should declare a generic type set() together with
the constraints on its argument. The constraint is the availability of
a comparison operation. This is satisfied for integer. If the
set_tools module also defines comparison for set(), generically using
comparison for the elements, then it qualifies set as a possible type
parameter of itself, and the above declaration makes sense.

Obviously, this is not current Fortran.

Now, the question is whether we can define a set of all sets that
doesn't include itself :-)

edmondo.g...@gmail.com

unread,
Sep 30, 2015, 5:21:28 AM9/30/15
to
There is another point, it should be assumed (or one have to specify) that whenever an operator is applied between intrinsic type it should be the standard intrinsic operator, or function.

So taking your example I would like to write:
ABSTRACT INTERFACE, intrinsic(operator(+))
FUNCTION plus_intf(lhs, rhs)
IMPORT :: t
TYPE(t), INTENT(IN) :: lhs, rhs
TYPE(t) :: plus_intf
END FUNCTION plus_intf
END INTERFACE

Meaning that whenever there is an intrinsic operator + defined between lhs and lhr it is that that is used.

edmondo.g...@gmail.com

unread,
Sep 30, 2015, 5:23:27 AM9/30/15
to
:-D :-D :-D

Ian Harvey

unread,
Sep 30, 2015, 7:09:59 AM9/30/15
to
On 2015-09-30 7:21 PM, edmondo.g...@gmail.com wrote:
> Il giorno mercoledì 30 settembre 2015 10:51:18 UTC+2, edmondo.g...@gmail.com ha scritto:
>> Il giorno mercoledì 30 settembre 2015 05:18:45 UTC+2, Ian Harvey ha scritto:
...
>> but let's assume we have a general container like a sorted list (like the std:set in C++).
>> And I want to have a sorted lists of sorted lists, using some operation to compare lists.
>>
>> How can be achieved that?

I would anticipate two use statements, creating two instantiations of
the parameterised module, with different actual parameters.

Assuming that there is a parameterised module named `sets` that takes a
single parameter of the type to be stored in the set, and defines the
type `set` to act as the container:

MODULE example
USE sets(my_type), set_of_my_type => set
USE sets(set_of_my_type), set_of_sets => set

TYPE(set_of_sets) :: my_set_of_sets

TYPE :: my_type
...
END TYPE my_type
END MODULE example


> There is another point, it should be assumed (or one have to specify) that whenever an operator is applied between intrinsic type it should be the standard intrinsic operator, or function.
>
> So taking your example I would like to write:
> ABSTRACT INTERFACE, intrinsic(operator(+))
> FUNCTION plus_intf(lhs, rhs)
> IMPORT :: t
> TYPE(t), INTENT(IN) :: lhs, rhs
> TYPE(t) :: plus_intf
> END FUNCTION plus_intf
> END INTERFACE
>
> Meaning that whenever there is an intrinsic operator + defined between lhs and lhr it is that that is used.

Perhaps I misunderstand, but if you have two objects of intrinsic type,
and you use the identifier for an intrinsic operation for an in-fix
operation between those two objects, how could it be interpreted to be
anything other than the intrinsic operation? You are not permitted to
redefine the intrinsic operators for the intrinsic operations that are
defined by the language.

Ian Harvey

unread,
Sep 30, 2015, 8:07:09 AM9/30/15
to
I am not familiar with the original proposal. As I envisage things,
there should be only one module for a particular package of generic
code, the concrete realisation of that generic code is driven by the use
statement that provides the actual parameters for the module.

What are the "implications about module dependency" that you refer to?

For contrast, I suggest:

use list_features(foo_t)
type(list) :: foo_list

versus your

use list_features
type(list(foo_t)) :: foo_list

For that case I think that's the same number of tokens, so I don't
consider this a simplification. Your approach would be simpler if there
were multiple lists instantiated for different types within the one
scope, however my approach would be simpler if there was more than one
object required from the same parameterisation within a scope.

Multiple lists:

use list_features(foo_t), foo_list_t => list
use list_features(bar_t), bar_list_t => list
type(foo_list_t) :: foo_list
type(bar_list_t) :: bar_list

versus

use list_features
type(list(foo_t)) :: foo_list
type(list(bar_t)) :: bar_list

Multiple objects:

use list_features(foo_t)
type(list) :: foo_list
type(list) :: foo_list2

versus

use list_features
type(list(foo_t)) :: foo_list
type(list(foo_t)) :: foo_list2

Some sort of type synonym facility (or FortranFan's module resolution
idea) may be useful to both concepts.

> Stated otherwise, working with lists (for instance) should be as
> straightforward as working with arrays. Working with sort (for
> instance) should be as forward as calling transpose.
>
> That said, there are uses for parameterized modules (aka functors),
> namely if there is a whole subpackage (e.g., a 'model') with multiple
> types, variables and procedures that depend on types or even whole
> modules, and which can be selected by the client code at compile time.
> But this is a bit clumsy if used for the simple purpose of defining a
> list or sorting of something.

As I noted in parentheses above, in some cases it might make sense to do
the parameterisation at the level of an isolated type or procedure.
Procedure level parameterisation would also help overcome some of the
issues trying to work with the language's current offering of kind
parameterised types.

But do consider the issues associated with the current kind
parameterised types. You can easily define them in the current
language, and instantiate instances of them, but actually trying to
provide procedures that do anything with them generically is a bloody
nuisance. You are practically forced to manually instantiate, ahead of
time, procedures for every possible value of the parameter, using
INCLUDE or some such nonsense. If I have a parameter that can take any
positive default integer value, then that is quite a few procedure
implementations! This is an absurd situation, practically rendering
kind parameterisation of derived types to nothing more than a namespace
nicety. That feature gap should not be repeated with parameterisation
of types on aspects other than an integer value.

Unlike some other languages, types in Fortran do not have member
procedures that are defined within the scope of the type. Instead types
in Fortran have bindings that reference procedures defined in a
different scope. I think that difference in language design needs to be
carefully considered when looking at how to add generic programming
capabilities.

There is also the issue of the possible need for "child" or dependent
types of your main parameterised type - for example iterators in the
STL. Fortran currently has no concept of a child type.

I think more often than not, a parameterised type will be provided and
used hand-in-hand with supporting procedures and child types, hence
instantiating them together as a package has some appeal.

But I am open to discussion around alternatives.

FortranFan

unread,
Sep 30, 2015, 9:19:55 AM9/30/15
to
On Wednesday, September 30, 2015 at 3:47:56 AM UTC-4, Arjen Markus wrote:

> ..
>
> Yes, I tried that renaming "trick" too and failed ;). Pity.
>

Been there, felt the pain - that was partly my motivation for the original post.

> But I thought of another thing that has not been mentioned here as far as I have seen and that is that Fortran has a lot of flexibility to work with its main container type, arrays of various dimensions.
>
> For instance: array operations, array sections and elemental routines. I know of nothing in C++ or C# or Java that comes close (C can't even begin to do something along those lines). I may be mistaken - my knowledge of Fortran far exceeds that of C++, C# and Java, but they are important aspects IMHO.
>
> ..

Yes, my hope is very much any additional support for generics for the two use cases I refer to in the original post i.e., generic methods (e.g., sorting, overloaded operators, etc.) or generic containers (lists, trees, stacks, queues, etc.) will build on all the valuable aspects of Fortran, especially with array handling and elemental procedures.

The syntax I suggested in the original post did strive to keep that in mind and thus came the suggestion to introduce minimal syntactical additions such as GENERIC :: TYPE to take care of multiple needs.

Wolfgang Kilian

unread,
Sep 30, 2015, 9:55:11 AM9/30/15
to
I may be misled, but consider

use list_features(foo_t)

type, private :: foo_t
end type

type (list) :: foo_list

so list_features(foo_t) is an independent module, an instance of generic
list_features(), which depends on the local type foo_t and has to export
again a list type into the current module - that's a circular
dependency. But it may be possible to state exceptions to the usual
rules in this context.
I feel a bit uneasy if naming issues become relevant. If the user has
to explicitly write list(foo_t), the type is explicit in every
declaration, while in the other syntax there is some temptation to write
just

use list_features(foo_t)
and later add
use list_features(bar_t), joes_list => list

so the reader of the code has to look up the appropriate use directive
in the file header. I like verbosity in the context of declarations.
No big deal otherwise, and there is always a way to obfuscate code, even
in Fortran.
There has to be a concept of parameterized procedures that goes along
with a parameterized type or module. The important part is that
procedure instances are created where used (the compiler may keep track
in order to not instantiate twice), instead of where defined. That's
relevant for any implementation of generic code. After all, all
executable code resides in procedures.

Ian Chivers

unread,
Sep 30, 2015, 10:06:23 AM9/30/15
to
In the C++ example I gave the templated quicksort works automatically
with any of the C++ intrinsic integer types (4 * signed and 4 * unsigned)
and real types (float, double and long double).

They find that you need to write 4 integer versions
(Fortran does not have unsigned) and 3 real versions in Fortran
a surprise.

FortranFan

unread,
Sep 30, 2015, 10:29:11 AM9/30/15
to
On Tuesday, September 29, 2015 at 11:18:45 PM UTC-4, Ian Harvey wrote:

> ..
>
> I think we are talking at cross purposes. Having the ability to
> "specify the minimum required characteristics of the dummy type" - i.e.
> constraints on the types that can be used - was one of my points.
>
> ..


"I think we are talking at cross purposes" - quite likely for my view is admittedly limited, summarized at a high level as possibly two use cases: generic methods and generic containers.

My primary goal here is simply to bring this up and hope those closer to the standards will notice and feel the nudge - given Damian Rouson's reply was highly reassuring in this regard.

Secondarily, I hope whatever solution that makes it in to the standard will require minimal syntactical additions such as GENERIC :: TYPE => which seems to build on Fortran 2003 through 2015 enhancements on the GENERIC keyword.

As I indicated from a strict OO language development and rigorous support for generics, having contraints focus of some minimal characteristics would make sense. A limited view in Fortran such as GENERIC :: TYPE => x where x can be either something new from ISO_FORTRAN_ENV intrinsic module e.g., ALL_INTRINSIC or ALL_INTEGER or ALL_INTEGER, ALL_REAL, etc. as well as TYPE(*) or TYPE(foo) seems ok to me, but I don't have the training/ability to think through such matters. Hence I'd rather leave this up to better minds and focus instead on planting and watering the seeds that may lead to more modern features in the language!!

Re: parameterized modules, since I'm rather biased in my view of Fortran MODULEs as namespaces and rightly or wrongly, I'm drawing an analogy with templated namespaces in C++ or generic namespaces in Java or C# i.e. their lack thereof, I wonder if there is something to learn from these other languages and/or why they didn't get added to Fortran if they were proposed for 2003 standard. Prima facie, the concept of parameterized modules does seem rather complicated.

Wolfgang Kilian

unread,
Sep 30, 2015, 10:39:19 AM9/30/15
to
For a language that supports all of parameterized modules, parameterized
procedures, and parameterized types, you may look into OCaml, which is a
functional language with procedural elements. There is something to
learn for Fortran, since this is a strongly typed and compiled language.
I'm sure there are others which I don't know.

FortranFan

unread,
Sep 30, 2015, 10:45:02 AM9/30/15
to
On Wednesday, September 30, 2015 at 10:06:23 AM UTC-4, Ian Chivers wrote:

> ..
> > Can you please elaborate what the C++ and C# people were trying to imply by their "air of incredulity"? I think I know the feeling because I work with a lot of C# (and some C++, declining due to migration toward C#) folks, but would like to be sure!
> >
>
> In the C++ example I gave the templated quicksort works automatically
> with any of the C++ intrinsic integer types (4 * signed and 4 * unsigned)
> and real types (float, double and long double).
>
> They find that you need to write 4 integer versions
> (Fortran does not have unsigned) and 3 real versions in Fortran
> a surprise.

Thanks much for your clarification.

It just goes to show how things can be made simpler for a Fortran coder if the language can be improved further with generic types.

As Damian Rouson mentioned earlier in this thread, language features such as this one and also other language facilities that make development easier for Fortran coders are very, very important "to stem the tide of defections to C++", etc.


Dan Nagle

unread,
Sep 30, 2015, 11:12:09 AM9/30/15
to
Hi,

If you want to make some progress on this, develop
a set of use-cases that generic programming should address.

Background

I've been trying to get WG5 and J3 to work on new revisions
of the standard from use-cases rather than more-or-less
completely developed new feature proposals. Hopefully, we will
be able to pay some attention to questions of strategic direction
rather than only details of specific proposals.

The idea is to have applications programmers indicate
the problems, and the committee subgroups can resolve
the details of a proposed cure.

I believe we can better serve the community by starting with use-cases.
Applications programmers can say what their issues are, and
compiler engineers can spot cases where the cost-benefit
of the feature is wrong and design around them.

If the only use-case for generic programming support is a sort routine,
the proposal will have a hard time (cost-benefit will be seen
as wrong due mainly to lack of benefit). Part of the exercise
is to define goals and part of the exercise is to prioritize
use of resources (mainly, compiler engineers' time).

Example

So I'll get the ball rolling . . .

I want some help with the following problem:

I have a file with a f77 library in it. I want to have a module
that will support all routines in the library for all (or most) real kinds
supported by several compilers. The compilers support different
numbers of real kinds with different kind values. I don't want
to force my users to recompile the module file every time it is used
but I do want the user to be able to select any kind value desired.
I do not want to use a macro preprocessor because that complicates
the build process (and I may hand this project to someone else
who may not have my priorities of software maintenance).

--
Cheers!

Dan Nagle

Jos Bergervoet

unread,
Sep 30, 2015, 1:56:13 PM9/30/15
to
On 9/30/2015 11:13 AM, Wolfgang Kilian wrote:
> On 30.09.2015 10:51, edmondo.g...@gmail.com wrote:
>> Il giorno mercoledì 30 settembre 2015
...
..
> Now, the question is whether we can define a set of all sets that
> doesn't include itself :-)

If you write it like that it is no more difficult then the set
of all numbers that doesn't include 5. I think most people would
accept the interpretation N\5 (the naturals with 5 excluded) is
a valid answer.

You really have to stick to: "the set of all sets that don't
contain themselves" to preserve the paradox, in my view. :^)

--
Jos

> -- Wolfgang
>
>
>

GianLuigi Piacentini

unread,
Sep 30, 2015, 3:33:45 PM9/30/15
to
Tried to follow this interesting discussion, but for my ignorance I'm
definitely lost...

Saw reference to C++ Java ... nobody cited the Ada way. I only know Ada for
name, but I know there is a lot of generics there. I do not know if Ada way
has issues, or can be more or less easily mapped to Fortran. I'm just saying
there is another solution where ideas can be taken.

I myself (hobby programs), I am interested in simple containers (bag, set,
queue, stack, list, deque, priority queue, selfbalancing btrees). Tried to
solve the simpler ones (bag, set for now, queue, stack planned) with
unlimited polymorphic, ended in being tired of SELECT TYPE, so tried with
some editing, something that can be done with a text editor (or a macro
processor, but probably there is no such need, I succeeded with a text
editor). Limits of this latter approach (standard Fortran 2008 gfortran
4.8.2 compilable) is that you have a container module for each type to be
contained (real::a, b -> one module, real ::a, complex :: b -> 2 modules),
and the user must supply a type copy procedure (and a less-than in case of
set), because the generic code does not know if default assignment and
default < are appropriate with what is stored. I think sort could be easily
solved this way. May be wrong, but anyway to be generic you must supply the
copy procedure and may be an equality and a less than test, that depend on
what is to be contained.

Apologizing if went off-topic

Gigi

FortranFan

unread,
Sep 30, 2015, 3:50:10 PM9/30/15
to
> ..

@Dan Nagle,

Thanks much for your comments, appreciate it greatly.

A few questions: first a procedural one and the remaining largely philosophical.

1. Where does one direct such things? Does WG5 and/or J3 have a site where Fortranners can post these queries? Or is there a mailing list for this?

2. How does one reconcile your "use case" approach for new language features with the consistency to be gained in terms of strategic direction vis-à-vis the duplication that may come about in the language? PROCEDURE facility in Fortran 2003 vs EXTERNAL and the enhancements to GENERIC statements in Fortran 2015 relative to INTERFACE blocks come to mind.

3. And what if one wants to combine multiple use cases and wants to challenge the standards body to come up with a common solution that takes all the use cases in mind which involves minimal syntactical additions to the language? That was a motivating idea in the original post for two use cases, for generic methods and generic containers.

4. What about the matter of design patterns or coding practices that might be established among many other practitioners (e.g., Java/C#) and/or some really big program developments (possibly at CERN or NASA or Sandia, now usually with C++) and the concept of bringing them to Fortran, the only benefits statement being the Field of Dreams idea, "build it and they will come."

4. Finally, what if one wants to engage the standards body toward obtaining a set of logical arguments as to why many of the brainwaves one gets (while doing actual coding!) on ideas to fill the glaring gaps noticed in the new features (say starting with Fortran 2003) would or would not be considered for discussion for a future standard revision? The original post in this thread is an example. The rationale with this is to understand the guiding principles or requirements or criteria, etc. by which things get accepted into the standard. I think this is important because a lot of good has happened to Fortran starting with 2003 standard and yet, there are aspects that feel loose-ended or unattended e.g., why PDTs were implemented they were, etc.. If it is all a matter of time and resources, one can fully understand; I, for one, would be highly considerate of such practical constraints. But if the reasons are true programming language design considerations involving syntax and semantics and so forth, then some like me can greatly benefit from some public disclosure on them.

Back to question 2, if one were to write up a use case for the changes made to GENERIC in Fortran 2015 along the lines you suggest, I can visualize a lot of reviewers rejecting it outright, saying "make do" with existing INTERFACE facility. However, my current impression is the changes to the GENERIC statement as indicated in the 2015 standard draft are really good and a welcome addition. Hence I imagine the use case and benefits statement for 2015 change has elements that I cannot put forward - is it possible to know how the 2015 change to GENERIC statement got introduced and accepted? By the way, you would have the suggestions in the original post are tied to the 2015 change to the GENERIC statement.

Beliavsky

unread,
Sep 30, 2015, 4:15:17 PM9/30/15
to
I have one for variables declared

real(kind=rkind)

where rkind can be set to be effectively single, double, or quadruple precision. The rkind is a module variable that is used by many other modules. Do other languages make it as easy to change the numerical precision of one's code?

glen herrmannsfeldt

unread,
Sep 30, 2015, 4:45:27 PM9/30/15
to
FortranFan <pare...@gmail.com> wrote:
> On Wednesday, September 30, 2015 at 10:06:23 AM UTC-4, Ian Chivers wrote:

(snip)
>> In the C++ example I gave the templated quicksort works automatically
>> with any of the C++ intrinsic integer types (4 * signed and 4 * unsigned)
>> and real types (float, double and long double).

>> They find that you need to write 4 integer versions
>> (Fortran does not have unsigned) and 3 real versions in Fortran
>> a surprise.

> Thanks much for your clarification.

> It just goes to show how things can be made simpler for a Fortran
> coder if the language can be improved further with generic types.

Having never actually written a C++ template, I read:

https://en.wikipedia.org/wiki/Template_(C%2B%2B)

> As Damian Rouson mentioned earlier in this thread, language
> features such as this one and also other language facilities
> that make development easier for Fortran coders are very,
> very important "to stem the tide of defections to C++", etc.

It seems that the compiler compiles a version for whichever
type(s) it sees in the source.

They have an example of a max function:

template <typename Type>
Type max(Type a, Type b) {
return a > b ? a : b;
}

Note that as written, the arguments and function itself have
the same type. The explanation shows that this works for
max(3,7) and max(3.0, 7.0), where the arguments are the same
type, and so is the result. It seems that it is compiler dependent
what happens if you do: max(3, 7.0).

On the other hand, C programmers write:

#define max(a,b) ((a) < (b) ? (b) : (a))

which is expanded inline and works for any type combination
that < works for. (The template also depends on <.)

Now, consider that one might want a generic cube root.

The square root routines that I know first divide the exponent
of the floating point value by two. (Easy, but system dependent
in assembler, a little harder in high-level languages.) Generate
an initial guess using simple linear approximations (and
different for initial exponent even or odd). Then two
(single precision) or four (double precision) iterations of
Newton-Raphson.

But how does the template know that two, four, or some other
number of iterations are needed? How does it know what a good
initial guess is? Note that this problem does not appear in
the max case, though that might be an unusually simple example.

Then there is the additional problem that people like to
distribute libraries of object programs knowing that it is
difficult for someone to decompile them and figure out how
they work. Templates, at least the C++ form, seem to be
distributed in human readable form.

-- glen


Ian Harvey

unread,
Sep 30, 2015, 5:06:48 PM9/30/15
to
From a distance, I can see attempts to plant seeds well over a decade
ago (perhaps two). To progress, things need to go beyond that, the
iterative process of considering requirements, developing options,
evaluating cost against benefit and fleshing out detail. That all
requires significant effort.

I think discussion on a forum like this can be a very useful part of
that effort.

> Re: parameterized modules, since I'm rather biased in my view of
> Fortran MODULEs as namespaces and rightly or wrongly, I'm drawing an
> analogy with templated namespaces in C++ or generic namespaces in
> Java or C# i.e. their lack thereof, I wonder if there is something to
> learn from these other languages and/or why they didn't get added to
> Fortran if they were proposed for 2003 standard. Prima facie, the
> concept of parameterized modules does seem rather complicated.

The vehicle for enabling parameterisation of code (and namespace
management) is different in those languages. I think the complexity
(for the same capability) more or less the same, it is just present in a
different area.

glen herrmannsfeldt

unread,
Sep 30, 2015, 5:08:23 PM9/30/15
to
FortranFan <pare...@gmail.com> wrote:

(snip)
> Yes, my hope is very much any additional support for generics for
> the two use cases I refer to in the original post i.e., generic
> methods (e.g., sorting, overloaded operators, etc.) or generic
> containers (lists, trees, stacks, queues, etc.) will build on
> all the valuable aspects of Fortran, especially with array
> handling and elemental procedures.

For Java, there are separate sort routines (overloaded) for
each primitive type (boolean, byte, short, char, int, long,
float, and double) and one for Object. The Object sort will
sort any array of Object of classes that implement Comparable.

The Object version will sort arrays of (references to) any kind
of Object. Even though they say that they aren't pointers,
arrays of Object work like pointers. Will Fortran generic
programmers be happy with arrays of pointers?

For the container types (List, Tree, Stack, Queue) Java only
supplies ones for Object. A have used HashMap with one element
arrays (arrays are Object in Java). This means an additional
level of indirection for every access.

-- glen

Ian Harvey

unread,
Sep 30, 2015, 5:22:06 PM9/30/15
to
On 2015-09-30 11:55 PM, Wolfgang Kilian wrote:
...
> There has to be a concept of parameterized procedures that goes along
> with a parameterized type or module. The important part is that
> procedure instances are created where used (the compiler may keep track
> in order to not instantiate twice), instead of where defined. That's
> relevant for any implementation of generic code. After all, all
> executable code resides in procedures.

This is perhaps a separate stream of discussion to your point, but one
aspect that requires careful thought with any parameterisation approach
is under what conditions are two instantiations considered the same
thing. I touched on that with my module example. This may apply to
procedures too, because of the possibility of SAVE'd local variables.

One simple approach would be to simply ban locally saved variables in
parameterised procedures, perhaps by regarding any local variable in the
procedure AS being automatic. Perhaps that loss of capability is
acceptable, perhaps not.

(Similarly you could also ban both module variables and saved local
variables from parameterised modules, and completely avoid the issue
there, but I thought that too restrictive.)

If you decide that you still want the ability to have local saved
variables, then you perhaps have the choice that every instantiation of
a parameterised procedure is a unique instance (that would require a
particular instantiation to be held via a procedure pointer or dummy
argument or similar for saved local variables to be useful, which might
be a bit arcane), or that every instantiation is common, regardless of
parameterisation (that would require any saved local variable to be
completely independent of the parameterisation, which might be a bit
restrictive), or some hybrid situation, such as having all
instantiations with the same parameters (however you define that) being
common (which might make life difficult for those trying to implement this).

Options aplenty, dragons in the details!

FortranFan

unread,
Sep 30, 2015, 6:11:55 PM9/30/15
to
On Wednesday, September 30, 2015 at 5:22:06 PM UTC-4, Ian Harvey wrote:

> ..
>
> This is perhaps a separate stream of discussion to your point, but one
> aspect that requires careful thought with any parameterisation approach
> is under what conditions are two instantiations considered the same
> thing. I touched on that with my module example. This may apply to
> procedures too, because of the possibility of SAVE'd local variables.
>
> One simple approach would be to simply ban locally saved variables in
> parameterised procedures,
>
> ..


A requirement that parameterized procedures has to be PURE seems like a good way to go, I don't know if there are any counter arguments.

> ..
>
> Options aplenty, dragons in the details!

Yep, hopefully the standards committee can renew their focus on these things once the coarray effort reaches a certain level of saturation, hopefully not much beyond 2017!




Ian Harvey

unread,
Sep 30, 2015, 6:20:40 PM9/30/15
to
On 2015-10-01 1:12 AM, Dan Nagle wrote:
> Hi,
>
> If you want to make some progress on this, develop
> a set of use-cases that generic programming should address.
...
> Example
>
> So I'll get the ball rolling . . .
>
> I want some help with the following problem:
>
> I have a file with a f77 library in it. I want to have a module
> that will support all routines in the library for all (or most) real kinds
> supported by several compilers. The compilers support different
> numbers of real kinds with different kind values. I don't want
> to force my users to recompile the module file every time it is used
> but I do want the user to be able to select any kind value desired.
> I do not want to use a macro preprocessor because that complicates
> the build process (and I may hand this project to someone else
> who may not have my priorities of software maintenance).

...and macro preprocessors that are language ignorant are horrible in
many other ways.

A variation on your example is when users want to have two instances of
your library active at the same time, with independent selection of kind
between those two instances. Perhaps the kind is the same, perhaps it
is different. This variation may be relevant, because it will break
some approaches to generic programming, given other language rules.

A further variation is where your library allows for two or more kind
parameters to be specified in the one instance - e.g. for some library
that tracks object locations with time I want to use single precision
for time quantities, double precision for distance quantities - this
variation starts off down the path of a combinatorial explosion that may
be a practical constraint for some approaches.

I have had to implement (perhaps via INCLUDE hack) many of the container
types in the C++ Standard Template Library. Pick pretty much any one of
those (perhaps apart from std::vector because Fortran's array support
helps a lot, but there are still material differences). In some cases
you can fudge a non-INCLUDE solution using unlimited polymorphic
objects, but that is not performant or succinct.

Another more Fortran specific example (first noting that possibilities
for helping with this may not necessarily involve generic programming)
is associated with the language design principle that if you want an
array of something where each element has to have the allocatable or
pointer attribute, then you need to write a wrapper type and use an
array of that type.

TYPE :: t(l)
INTEGER, LEN :: l
!...
END TYPE t

! Now I want an array of t, where each element has a
! different length (or if the component is an array,
! different size, or if the component is polymorphic,
! different dynamic type).
TYPE t_element
TYPE(t), ALLOCATABLE :: item
END TYPE t_element

TYPE(t_element), ALLOCATABLE :: array(xxx)

Then invariably I have some common operations on rank one arrays of that
type - efficiently grow the array and move or copy an item in,
efficiently shrink the array, search the array for a particular value,
etc. I end up with nearly the same token sequence, bar the names of the
types and the details of the component, repeated multiple times in my code.

Ian Harvey

unread,
Sep 30, 2015, 7:41:02 PM9/30/15
to
On 2015-10-01 8:11 AM, FortranFan wrote:
> On Wednesday, September 30, 2015 at 5:22:06 PM UTC-4, Ian Harvey wrote:
>
>> ..
>>
>> This is perhaps a separate stream of discussion to your point, but one
>> aspect that requires careful thought with any parameterisation approach
>> is under what conditions are two instantiations considered the same
>> thing. I touched on that with my module example. This may apply to
>> procedures too, because of the possibility of SAVE'd local variables.
>>
>> One simple approach would be to simply ban locally saved variables in
>> parameterised procedures,
>>
>> ..
>
>
> A requirement that parameterized procedures has to be PURE seems like a good way to go, I don't know if there are any counter arguments.

The obvious one is that a requirement for PURE is a pretty major
restriction! Consider the restrictions around pointers, polymorphic
objects, external input/output, image control statements...

>> ..
>>
>> Options aplenty, dragons in the details!
>
> Yep, hopefully the standards committee can renew their focus on these things once the coarray effort reaches a certain level of saturation, hopefully not much beyond 2017!

My understanding is that there are only a handful of people on the
committee. Expecting them to be solely responsible for language
evolution, particularly around major additions like this, is
unreasonable, and for some of them, perhaps a little contrary to the
interests of the organisations that sponsor their membership of the
committee.

So rather than deferring everything to them, why not do some of the
development in the broader Fortran community? As an individual with a
keen interest in the language and its future, I'll put my hand up to put
some real effort into such a thing.

James Van Buskirk

unread,
Sep 30, 2015, 10:21:09 PM9/30/15
to
"Ian Chivers" wrote in message
news:560BEC5C...@chiversandbryan.co.uk...
Given implicit typing, the programmer needs only write one
version, but you might have to compile 9 versions to get all
real and integer kinds.

D:\gfortran\clf\qsort>type quicksort.i90
recursive subroutine quicksort_template(Qarray)
dimension Qarray(:)
integer i, j
i = lbound(Qarray,1)
j = ubound(Qarray,1)
Qv = Qarray((i+j)/2)
do
do while(Qarray(i) < Qv)
i = i+1
end do
do while(Qv < Qarray(j))
j = j-1
end do
if(i <= j) then
Qarray([i,j]) = Qarray([j,i])
i = i+1
j = j-1
end if
if(i > j) exit
end do
if(lbound(Qarray,1) < j) call quicksort_template(Qarray(:j))
if(i < ubound(Qarray,1)) call quicksort_template(Qarray(i:))
end subroutine quicksort_template

D:\gfortran\clf\qsort>type qsort.f90
module dqsort
implicit real(kind([double precision::])) (Q)
private
public quicksort
interface quicksort
module procedure quicksort_template
end interface quicksort
contains
include 'quicksort.i90'
end module dqsort

module iqsort
implicit integer(kind([integer::])) (Q)
private
public quicksort
interface quicksort
module procedure quicksort_template
end interface quicksort
contains
include 'quicksort.i90'
end module iqsort

module allqsort
use dqsort
use iqsort
end module allqsort

program main
use allqsort
implicit none
double precision :: da(10) = &
[1.9d0,8.2d0,3.7d0,6.4d0,5.5d0,1.8d0,9.2d0,3.6d0,7.4d0,5.5d0]
integer :: ia(10) = [1,10,2,9,3,8,4,7,6,5]
character(80) fmt
call quicksort(da)
write(fmt,'(*(g0))') '(',"' [ '",size(da),'(g0,1x)',"']'",')'
write(*,'(a)') ' Quicksort of double array is '
write(*,fmt) da
call quicksort(ia)
write(fmt,'(*(g0))') '(',"' [ '",size(ia),'(g0,1x)',"']'",')'
write(*,'(a)') ' Quicksort of integer array is '
write(*,fmt) ia
end program main

D:\gfortran\clf\qsort>ifort /nologo qsort.f90
qsort.f90(2): error #5082: Syntax error, found IDENTIFIER 'PRECISION' when
expec
ting one of: .EQV. .NEQV. .XOR. .OR. .AND. .LT. < .LE. <= .EQ. == .NE. /=
.GT. >
...
implicit real(kind([double precision::])) (Q)
------------------------------^
qsort.f90(13): error #5082: Syntax error, found '(' when expecting one of: (
implicit integer(kind([integer::])) (Q)
---------------------------------------^
qsort.f90(17): error #5082: Syntax error, found IDENTIFIER
'QUICKSORT_TEMPLATE'
when expecting one of: <END-OF-STATEMENT> ;
module procedure quicksort_template
-----------------------^
qsort.f90(21): error #5082: Syntax error, found 'MODULE' when expecting one
of:
<END-OF-STATEMENT> ; FUNCTION SUBROUTINE
end module iqsort
----^
qsort.f90(21): error #6818: The statement following a CONTAINS is not a
function
-stmt or a subroutine-stmt.
end module iqsort
^
qsort.f90(21): error #6702: END statement confusion.
end module iqsort
^
qsort.f90(29): error #7013: This module file was not generated by any
release of
this compiler. [ALLQSORT]
use allqsort
-------^
compilation aborted for qsort.f90 (code 1)

Oops, ifort blows up for no apparent reason. So on with gfortran:

D:\gfortran\clf\qsort>gfortran qsort.f90 -oqsort

D:\gfortran\clf\qsort>qsort
Quicksort of double array is
[ 1.8000000000000000 1.8999999999999999 3.6000000000000001
3.7000000000000002 5
.5000000000000000 5.5000000000000000 6.4000000000000004 7.4000000000000004
8.199
9999999999993 9.1999999999999993 ]
Quicksort of integer array is
[ 1 2 3 4 5 6 7 8 9 10 ]

FortranFan

unread,
Sep 30, 2015, 11:18:35 PM9/30/15
to
On Wednesday, September 30, 2015 at 7:41:02 PM UTC-4, Ian Harvey wrote:

> On 2015-10-01 8:11 AM, FortranFan wrote:
> ..
> >
> > A requirement that parameterized procedures has to be PURE seems like a good way to go, I don't know if there are any counter arguments.
>
> The obvious one is that a requirement for PURE is a pretty major
> restriction! Consider the restrictions around pointers, polymorphic
> objects, external input/output, image control statements...
>

Almost all the use cases I've for generic methods (that's what is meant by parameterized procedures, I assume) are like those providing overloaded operators in the original post and the sorting/swapping routines of the kind mentioned by Ian Chivers are PURE. But if there are good use cases where PURE won't cut it, bigger tent then.. It feels rather odd then to conceive of an isolated criteria like no SAVEd local variables and not applying a broader principle such a purity,

> ..
>
> So rather than deferring everything to them, why not do some of the
> development in the broader Fortran community? As an individual with a
> keen interest in the language and its future, I'll put my hand up to put
> some real effort into such a thing.

Crowdsourcing to lead to a proposal - all power to you, Godspeed!

Ian Harvey

unread,
Sep 30, 2015, 11:54:00 PM9/30/15
to
On 2015-10-01 6:15 AM, Beliavsky wrote:
...
> I have one for variables declared
>
> real(kind=rkind)
>
> where rkind can be set to be effectively single, double, or quadruple
> precision. The rkind is a module variable that is used by many other
> modules. Do other languages make it as easy to change the numerical
> precision of one's code?

Yes. Consider the typedef facility of C and C++.




glen herrmannsfeldt

unread,
Oct 1, 2015, 12:54:37 AM10/1/15
to
Beliavsky <beli...@aol.com> wrote:
> On Wednesday, September 30, 2015 at 10:06:23 AM UTC-4, Ian Chivers wrote:

(snip)
>> In the C++ example I gave the templated quicksort works automatically
>> with any of the C++ intrinsic integer types (4 * signed and 4 * unsigned)
>> and real types (float, double and long double).

(snip)

> I have one for variables declared

> real(kind=rkind)

> where rkind can be set to be effectively single, double, or
> quadruple precision. The rkind is a module variable that is
> used by many other modules. Do other languages make it as
> easy to change the numerical precision of one's code?

I never knew anyone to do it, but the PL/I preprocessor
could do that, and should be able to do much more complicated
generics. For one, it has a DO loop such that you can
generate an appropriate set of statements, such as an unrolled
loop. There are only strings and fixed point numeric data types
available for preprocessor variables, so you can't do really
complicated things at compile time.

-- glen

Arjen Markus

unread,
Oct 1, 2015, 3:23:07 AM10/1/15
to
Op woensdag 30 september 2015 17:12:09 UTC+2 schreef Dan Nagle:
> Hi,
>
> If you want to make some progress on this, develop
> a set of use-cases that generic programming should address.

>
> Example
>
> So I'll get the ball rolling . . .
>
> I want some help with the following problem:
>
> I have a file with a f77 library in it. I want to have a module
> that will support all routines in the library for all (or most) real kinds
> supported by several compilers. The compilers support different
> numbers of real kinds with different kind values. I don't want
> to force my users to recompile the module file every time it is used
> but I do want the user to be able to select any kind value desired.
> I do not want to use a macro preprocessor because that complicates
> the build process (and I may hand this project to someone else
> who may not have my priorities of software maintenance).
>

I am dealing with exactly this kind of problem. In my case it is the PLplot plotting package (plplot.sf.net). Currently you have to specify the kind of reals you want to use at compile time (this is a problem for the Fortran bindings, as most other languages supported within the PLplot project don't bother with single precision). I have devised a way of creating a dual set of routines - without doubling the source code! - so that two versions are present in the library and the right version is selected at compile time without any bother for the programmer.

My solution:
- Put the relevant source code in an include file, with all the real variables of the kind "wp".
- Define two modules: one where "wp" is set to single precision and another one where it is set to double precision.
- Define a third module that includes the previous two and has the code for those routines that are "kind-neutral".

The Fortran programmer then uses the third module.

Here is the source code for this set-up (leaving out the bits that are not relevant here):


module plplot_types
include 'plplot_interface_private_types.inc'
end module plplot_types

module plplot_single
use, intrinsic :: iso_c_binding
use plplot_types, wp => private_single

private :: wp, private_single, private_double, private_plint, private_plunicode

include 'plplot_interfaces.inc'
end module plplot_single

module plplot_double
use, intrinsic :: iso_c_binding
use plplot_types, wp => private_double

private :: wp, private_single, private_double, private_plint, private_plunicode

include 'plplot_interfaces.inc'

end module plplot_double

module plplot
use plplot_single
use plplot_double
use plplot_types, only: plflt => private_plflt, private_plint, private_plunicode

include 'plplot_parameters.inc'
private :: private_plint, private_plunicode
!
! Interfaces that do not depend on the real kind
!
...
end module plplot

This is a bit more complicated than may be necessary in many other cases, but we want to be as platform-independent as possible, so some parts are configured by the build tools.

Regards,

Arjen

Arjen Markus

unread,
Oct 1, 2015, 3:29:27 AM10/1/15
to
Op donderdag 1 oktober 2015 04:21:09 UTC+2 schreef James Van Buskirk:

>
> Given implicit typing, the programmer needs only write one
> version, but you might have to compile 9 versions to get all
> real and integer kinds.
>

I have been thinking about various solutions to the problem and it might make a nice article (as I have hinted at in private to Ian), but here is the one I kind-of like. No tricks involved (renaming or includes), just unlimited polymorphs. Caveat: not all compilers/versions of compilers can handle it:

! quicksort.f90 --
! Implement a generic QUICKSORT
!
! Numeric basic types and a sortable class supported
!
module quicksort_def
implicit none

type, abstract :: sortable
!integer :: value
contains
procedure(assign_object), deferred :: copy
procedure(one_lower_than_two), deferred :: lower
end type sortable

abstract interface
subroutine assign_object( left, right )
import :: sortable
class(sortable), intent(inout) :: left
class(sortable), intent(in) :: right
end subroutine assign_object
end interface

abstract interface
logical function one_lower_than_two( op1, op2 )
import :: sortable
class(sortable), intent(in) :: op1, op2
end function one_lower_than_two
end interface

interface operator(<)
module procedure lower
end interface

contains
!
! Generic part
!
logical function lower( op1, op2 )
class(*), intent(in) :: op1, op2

select type (op1)
type is (integer)
select type (op2)
type is (integer)
lower = op1 < op2
end select

type is (real)
select type (op2)
type is (real)
lower = op1 < op2
end select

class is (sortable)
select type (op2)
class is (sortable)
lower = op1%lower(op2)
end select
end select
end function lower

subroutine copy( op1, op2 )
class(*) :: op1, op2

select type (op1)
type is (integer)
select type (op2)
type is (integer)
op1 = op2
end select

type is (real)
select type (op2)
type is (real)
op1 = op2
end select

class is (sortable)
select type (op2)
class is (sortable)
call op1%copy( op2 )
end select
end select
end subroutine copy

recursive subroutine quicksort( array )
class(*), dimension(:) :: array

class(*), allocatable :: v, tmp
integer :: i, j

i = 1
j = size(array)

allocate( v, source = array(1) )
allocate( tmp, source = array(1) )

call copy( v, array((j+i)/2) ) ! Use the middle element

do
do while ( array(i) < v )
i = i + 1
enddo
do while ( v < array(j) )
j = j - 1
enddo

if ( i <= j ) then
call copy( tmp, array(i) )
call copy( array(i), array(j) )
call copy( array(j), tmp )
i = i + 1
j = j - 1
endif

if ( i > j ) then
exit
endif
enddo

if ( 1 < j ) then
call quicksort( array(1:j) )
endif
if ( i < size(array) ) then
call quicksort( array(i:) )
endif
end subroutine quicksort

end module quicksort_def


! test program
program test_quicksort
use quicksort_def

implicit none

integer, dimension(10) :: int_array
real, dimension(10) :: real_array
integer :: i

do i = 1,size(int_array)
int_array(i) = 11 - i
real_array(i) = 11.0 - i
enddo

write(*,*) 'Sorting ...'
call quicksort( int_array )
call quicksort( real_array )

write(*,*) 'Result:'
write(*,'(i10)') int_array
write(*,'(f10.2)') real_array

end program test_quicksort

Regards,

Arjen

Wolfgang Kilian

unread,
Oct 1, 2015, 3:49:24 AM10/1/15
to
I think there is an obvious place to look for use cases.

The domain of Fortran is scientific/numeric programming. Leaving aside
proprietary code, there are two other languages most frequently used in
that area: C++ and Python. C++ is compiled and actually competitive
with Fortran. Python is not competitive regarding efficiency, but
accepted as 'convenient'.

So, it does make sense to query C++ (Python) for features that are
frequently used in science/tech but missing in Fortran. Subtract
features for which Fortran offers better solutions. Accept that there
are good reasons (for some people) to prefer C++ (Python) over Fortran.

I'm quite sure that you would start off from parts of the STL. C++
enables you to throw unstructured data in a bin until they are digested
without caring about array size, memory and ordering, but keeping type
safety and reasonable efficiency. (C++ also allows you shooting in the
foot instead.) Python has hashes. In Fortran, you may map this to
arrays but it quickly becomes cumbersome and awkward. You may map this
to pointer structures, but then you'll write all code yourself. Out of
the box, Fortran deals well with structured, preprocessed data.

In short, type-safe containers such as vector, stack, queue and the like
make obvious use cases that would be immediately accepted by Fortran
practitioners. Also think of generic tree structures.

Implementation is another story. The Fortran standard might just
provide something similar to (useful parts of) the STL. However, there
are lots of variants. Probably a generic facility is more economic.
This doesn't imply that a Fortran version has to parallel C++ templates
in syntax or mimic the STL, but it should somehow cover those use cases.
Regarding containers, I'm not sure how iterators should look like in
Fortran.

If there is real interest, this might be put into a more concrete form.
I guess that use cases could be formulated as suggestions for syntax
and semantics that use generic code but leave open the definition of the
generic.

Wolfgang Kilian

unread,
Oct 1, 2015, 4:00:31 AM10/1/15
to
... also saw the flaw on second reading, thanks for correcting this.
Now provide the code.

FX

unread,
Oct 1, 2015, 6:04:13 AM10/1/15
to
> But how does the template know that two, four, or some other number of
> iterations are needed?

You can mark some code as dependent on the actual type of arguments. One
way is to check for type equality:

$ cat a.cpp
#include <iostream>
#include <type_traits>

template <typename T>
void foo (T arg)
{
const int n = std::is_same<T,float>::value ? 2 : 4;
std::cout << "n = " << n << std::endl;
}


int main (void)
{
foo (1.0f);
foo (1.0);
return 0;
}
$ g++ a.cpp && ./a.out
n = 2
n = 4


Another is to write your generic macro with the bulk of the code
(abstracting what can be abstracted) and use a specialized subfunction
for the rest:

$ cat b.cpp
#include <iostream>

template <typename T> int niter (T arg) { return 2; }
template <> int niter (double arg) { return 4; }

template <typename T>
void foo (T arg)
{
int n = niter(arg);
std::cout << "n = " << n << std::endl;
/* The common code would go there. */
}

int main (void)
{
foo (1.0f);
foo (1.0);
return 0;
}

$ g++ b.cpp && ./a.out
n = 2
n = 4



Of course, if the code in each case is entirely different, it makes no sense
to use templates at all.

--
FX

fj

unread,
Oct 1, 2015, 9:15:19 AM10/1/15
to
Nice Arjen !

Arjen Markus

unread,
Oct 1, 2015, 9:37:56 AM10/1/15
to
Op donderdag 1 oktober 2015 15:15:19 UTC+2 schreef fj:
Thanks :)

Regards,

Arjen

Gary Scott

unread,
Oct 1, 2015, 9:43:37 AM10/1/15
to
Don't most compilers provide a built in quicksort? :)

Wolfgang Kilian

unread,
Oct 1, 2015, 9:53:35 AM10/1/15
to
On 30.09.2015 23:22, Ian Harvey wrote:
> On 2015-09-30 11:55 PM, Wolfgang Kilian wrote:
> ...
>> There has to be a concept of parameterized procedures that goes along
>> with a parameterized type or module. The important part is that
>> procedure instances are created where used (the compiler may keep track
>> in order to not instantiate twice), instead of where defined. That's
>> relevant for any implementation of generic code. After all, all
>> executable code resides in procedures.
>
> This is perhaps a separate stream of discussion to your point, but one
> aspect that requires careful thought with any parameterisation approach
> is under what conditions are two instantiations considered the same
> thing. I touched on that with my module example. This may apply to
> procedures too, because of the possibility of SAVE'd local variables.

Yes, that is one of many issues that have to be sorted out.

My personal approach would be that

1) parameterized modules have to be explicitly instantiated, so it is
clear where an instance resides and how it is accessed. That is, a
module variable is a member of a named instance. There can be distinct
instances with identical type parameters.

I guess that module variables of generic type would be a motivation of
introducing parameterized modules. If there is an explicit instance,
the scope of that module variable is defined.

> One simple approach would be to simply ban locally saved variables in
> parameterised procedures, perhaps by regarding any local variable in the
> procedure AS being automatic. Perhaps that loss of capability is
> acceptable, perhaps not.

2) parameterized procedures are implicitly instanced, that is, the
subroutine is generic in the definition module

module gen
[declaration of gen_type]
contains
abstract subroutine foo (x)
type(gen_type) :: x
end subroutine foo
end module gen

but the client code doesn't refer to this at all

use gen, only: foo
type(some_type) :: x

call foo (x)

legal if some_type matches the requirements for gen_type. The caller
uses the subroutine as if it had been written for some_type explicitly
or if there existed an INTERFACE to a module procedure for some_type.

BTW, TKR resolution may first look for module procedures with an
INTERFACE and next for a matching abstract procedures (in the latter
case, name has to be unique). This makes it easy to override generic
code by more efficient specific code.

The subroutine instance would have access to members of some_type only
if they are (public and) declared in the gen_type constraints. It would
have access to module variables of module gen.

I think that SAVED local variables of generic procedure should be unique
in the program, so there is effectively only one instance for a
particular type parameter combination. This is the expectation for an
ordinary specific procedure. But personally, I have no problem with
banning SAVED local variables here. For a long time, I have regarded
them as an artifact from F77 that is superseded by module variables.

Requiring PURE is way too strong. PURE severely restricts I/O, which is
no issue here.
>
> (Similarly you could also ban both module variables and saved local
> variables from parameterised modules, and completely avoid the issue
> there, but I thought that too restrictive.)
>
> If you decide that you still want the ability to have local saved
> variables, then you perhaps have the choice that every instantiation of
> a parameterised procedure is a unique instance (that would require a
> particular instantiation to be held via a procedure pointer or dummy
> argument or similar for saved local variables to be useful, which might
> be a bit arcane), or that every instantiation is common, regardless of
> parameterisation (that would require any saved local variable to be
> completely independent of the parameterisation, which might be a bit
> restrictive), or some hybrid situation, such as having all
> instantiations with the same parameters (however you define that) being
> common (which might make life difficult for those trying to implement
> this).
>
> Options aplenty, dragons in the details!


Wolfgang Kilian

unread,
Oct 1, 2015, 10:09:42 AM10/1/15
to
On 01.10.2015 09:29, Arjen Markus wrote:
> Op donderdag 1 oktober 2015 04:21:09 UTC+2 schreef James Van Buskirk:
>
>>
>> Given implicit typing, the programmer needs only write one
>> version, but you might have to compile 9 versions to get all
>> real and integer kinds.
>>
>
> I have been thinking about various solutions to the problem and it might make a nice article (as I have hinted at in private to Ian), but here is the one I kind-of like. No tricks involved (renaming or includes), just unlimited polymorphs. Caveat: not all compilers/versions of compilers can handle it:

Sorry, but I'd say the code below illustrates the problem rather than
solving it. First of all, you still need 9 versions to get all real and
integer kinds. They are distributed in various SELECT TYPE clauses, and
you will run into difficulties if a kind is absent for some compiler or
two named kinds coincide.

Second, you require the user to extend a base type SORTABLE. However,
the user type will in general already be an extension of some base type.
It is not good design to enforce a class hierarchy if the only purpose
is adding a particular procedure.

I guess this is an obvious use case where only actual generic
programming can resolve the issue in a satisfactory way.

-- Wolfgang

edmondo.g...@gmail.com

unread,
Oct 1, 2015, 11:34:55 AM10/1/15
to
About the notorious sets of sets, assuming that, as the std::set in C++, they are ordered, we may have to write something like this:

module setset
use gen_set,only: set

type(set(set(integer))):: a

interface operator(<)
module procedure lowthen
end interface

contains

logical function lowthen(this, that)
type(set(integer)),intent(in) :: this, that
!retrieve the elements and return true if this < that
end function
end module

Or if one want to have something more OO, an additional defined type should be inserted like we do with pointers:

module setset
use gen_set,only: set

type integerset
type(set(integer)) :: elem
contains
generic :: operator(<) => lowthen
procedure :: lowthen
end type

type(set(integerset)):: a

interface operator(<)
module procedure lowthen
end interface

contains

logical function lowthen(this, that)
type(integerset),intent(in) :: this, that
! return true if this%elem < that%elem
end function
end module

Jos Bergervoet

unread,
Oct 1, 2015, 12:29:44 PM10/1/15
to
For the set that doesn't include 5? Well, here's the characteristic
function:

pure elemental logical function isInSet( n )
integer, value :: n
isInSet = n /= 5
end

The astute reader will now be able to apply this to the other
examples as well.

For extra bonus points show how to make the set fuzzy or how to
give it quantum mechanical properties, by adjusting the type of
the function. (This will also keep the thread more on-topic).

--
Jos

Dan Nagle

unread,
Oct 1, 2015, 1:16:52 PM10/1/15
to
Hi,

On 2015-09-30 19:50:03 +0000, FortranFan said:

> 1. Where does one direct such things? Does WG5 and/or J3 have a site
> where Fortranners can post these queries? Or is there a mailing list
> for this?

Well, no, not really. Several committee members read c.l.f, comp-fortran-90,
and linkedin Fortran comments.

>
> 2. How does one reconcile your "use case" approach for new language
> features with the consistency to be gained in terms of strategic
> direction vis-à-vis the duplication that may come about in the
> language? PROCEDURE facility in Fortran 2003 vs EXTERNAL and the
> enhancements to GENERIC statements in Fortran 2015 relative to
> INTERFACE blocks come to mind.

I suppose you could try to make a strategic plan.

>
> 3. And what if one wants to combine multiple use cases and wants to
> challenge the standards body to come up with a common solution that
> takes all the use cases in mind which involves minimal syntactical
> additions to the language? That was a motivating idea in the original
> post for two use cases, for generic methods and generic containers.

One can create a higher-rank array using any type in Fortran,
so I think the generic containers argument is a bit weak.
With the generic methods, what tasks are you trying to solve?

>
> 4. What about the matter of design patterns or coding practices that
> might be established among many other practitioners (e.g., Java/C#)
> and/or some really big program developments (possibly at CERN or NASA
> or Sandia, now usually with C++) and the concept of bringing them to
> Fortran, the only benefits statement being the Field of Dreams idea,
> "build it and they will come."

There is a Fortran Annex for the Vulnerabilities TS published by WG23.

> 4. Finally, what if one wants to engage the standards body toward
> obtaining a set of logical arguments as to why many of the brainwaves
> one gets (while doing actual coding!) on ideas to fill the glaring gaps
> noticed in the new features (say starting with Fortran 2003) would or
> would not be considered for discussion for a future standard revision?
> The original post in this thread is an example. The rationale with
> this is to understand the guiding principles or requirements or
> criteria, etc. by which things get accepted into the standard. I think
> this is important because a lot of good has happened to Fortran
> starting with 2003 standard and yet, there are aspects that feel
> loose-ended or unattended e.g., why PDTs were implemented they were,
> etc.. If it is all a matter of time and resources, one can fully
> understand; I, for one, would be highly considerate of such practical
> constraints. But if the reasons are true programming language design
> considerations involving syntax and semantics and so forth, then some
> like me can greatly benefit from some public disclosure on them.

Join the committee and express yourself.

>
> Back to question 2, if one were to write up a use case for the changes
> made to GENERIC in Fortran 2015 along the lines you suggest, I can
> visualize a lot of reviewers rejecting it outright, saying "make do"
> with existing INTERFACE facility. However, my current impression is
> the changes to the GENERIC statement as indicated in the 2015 standard
> draft are really good and a welcome addition. Hence I imagine the use
> case and benefits statement for 2015 change has elements that I cannot
> put forward - is it possible to know how the 2015 change to GENERIC
> statement got introduced and accepted? By the way, you would have the
> suggestions in the original post are tied to the 2015 change to the
> GENERIC statement.

Making lots of little fixes rather than fewer bigger fixes is difficult
without a plan. The standards could spend as much compiler engineers' time
with a pile a little stuff as it could with one or two bigger features
that would have longer-lasting effects.

I want to escape the "I need a FUBAR statement" (or a SNAFU clause on
the existing
FUBAR ststement). What are you trying to do that you need a SNAFU statement?

--

Cheers!
Dan Nagle

Wolfgang Kilian

unread,
Oct 1, 2015, 1:34:17 PM10/1/15
to
On 10/01/2015 06:29 PM, Jos Bergervoet wrote:
> On 10/1/2015 10:00 AM, Wolfgang Kilian wrote:
>> On 30.09.2015 19:55, Jos Bergervoet wrote:
>>> On 9/30/2015 11:13 AM, Wolfgang Kilian wrote:
>>>> On 30.09.2015 10:51, edmondo.g...@gmail.com wrote:
>>>>> Il giorno mercoledì 30 settembre 2015
>>> ...
>>> ..
>>>> Now, the question is whether we can define a set of all sets that
>>>> doesn't include itself :-)
>>>
>>> If you write it like that it is no more difficult then the set
>>> of all numbers that doesn't include 5. I think most people would
>>> accept the interpretation N\5 (the naturals with 5 excluded) is
>>> a valid answer.
>>>
>>> You really have to stick to: "the set of all sets that don't
>>> contain themselves" to preserve the paradox, in my view. :^)
>>
>> ... also saw the flaw on second reading, thanks for correcting this. Now
>> provide the code.
>
> For the set that doesn't include 5?

Well, no, I meant ... :-)

Well, here's the characteristic
> function:
>
> pure elemental logical function isInSet( n )
> integer, value :: n
> isInSet = n /= 5
> end
>
> The astute reader will now be able to apply this to the other
> examples as well.

> For extra bonus points show how to make the set fuzzy or how to
> give it quantum mechanical properties, by adjusting the type of
> the function. (This will also keep the thread more on-topic).
>

[The quantum-mechanical set sounds interesting. First of all, the
characteristic function should return a qbit. That sounds like
something to be added soon to the language. We might need a
superposition of qbit arrays (strings) of undetermined length, so I'll
suggest to add QUANTUM ELEMENTAL as a procedure qualifier. Of course,
this implies PURE, otherwise there would be code decoherence. The rest
is left for the committee to sort out.]

-- Wolfgang

glen herrmannsfeldt

unread,
Oct 1, 2015, 2:06:25 PM10/1/15
to
FX <cou...@alussinan.org> wrote:

(I previously wrote)
>> But how does the template know that two, four, or some other number of
>> iterations are needed?

> You can mark some code as dependent on the actual type of arguments.
> One way is to check for type equality:

> $ cat a.cpp
> #include <iostream>
> #include <type_traits>

> template <typename T>
> void foo (T arg)
> {
> const int n = std::is_same<T,float>::value ? 2 : 4;
> std::cout << "n = " << n << std::endl;
> }

> int main (void)
> {
> foo (1.0f);
> foo (1.0);
> return 0;
> }
> $ g++ a.cpp && ./a.out
> n = 2
> n = 4

OK, but I meant it in terms of how the template writer
knows, but this part is also needed.

> Another is to write your generic macro with the bulk of the code
> (abstracting what can be abstracted) and use a specialized subfunction
> for the rest:

(snip)

> Of course, if the code in each case is entirely different,
> it makes no sense to use templates at all.

Years ago, I used to read the OS/360 Fortran library routines.
(Figuring out those is pretty much how I learned assembly
programming.) I also had the IBM manual describing the
algorithms.

Newton-Raphson doubles the number of digits for each iteration,
so there is a balance between the first approximation and the
number of iterations. For the known cases of IEEE floating
point, one could compute the them separately when writing
the template, then supply the appropriate number of N-R
iterations.

Is there a way in C++ templates to generate the appropriate
number of N-R steps? The routines that I know of unroll
the loop. Maybe now you depend on the compiler to do it.

If you want to allow for more than IEEE floating point, there
are more possibilities to consider.

Cube root is fairly simple as numerical algorithms go, but
already shows that you need to carefully consider how to do it.
(I was considering cube root, as all libraries, and much
hardware, already have square root.)

-- glen


FX

unread,
Oct 1, 2015, 3:08:44 PM10/1/15
to
> Newton-Raphson doubles the number of digits for each iteration, so
> there is a balance between the first approximation and the number of
> iterations. For the known cases of IEEE floating point, one could
> compute the them separately when writing the template, then supply the
> appropriate number of N-R iterations.

Yes, some parts and parameters of every algorithm need to be fine-tuned
and optimized, either analytically or through testing. No programming
language is going to do that for you, templates or not :)

> Is there a way in C++ templates to generate the appropriate number of
> N-R steps? The routines that I know of unroll the loop. Maybe now you
> depend on the compiler to do it.

The compiler is going to unroll the loops, but you can also play tricks
with the templates to generate certain number of iterations without loop.

--
FX

glen herrmannsfeldt

unread,
Oct 1, 2015, 5:33:22 PM10/1/15
to
Gary Scott <garyl...@sbcglobal.net> wrote:

(big snip)

> Don't most compilers provide a built in quicksort? :)

Well, technically the libraries provide it.

In the case of gcc, the library is traditionally not part of
the compiler. (Though the C library is part of the C standard.)

But yes, qsort() is a standard part of the C library
(though it may or may not be implemented as quicksort).

The problem isn't how to write quicksort, but how to write
a generic routine to do it. You need a way to compare two
array entries, and a way to exchange two entries.

In the C case, you supply a function that is passed pointers
to two array elements. With (void*) in C, you can easily pass
pointers to objects without knowing anything about what is
being pointed to. Only the compare routine needs to know.

C allows for copying blocks of memory if you have pointers
and the number of bytes (from sizeof) that need to be copied.
That allows swapping array element of unknown content.

A more common way to use C's qsort() is to sort a list of
pointers to the data. That is, for example, the only way to do
it in Java. (Well, references, you aren't supposed to call them
pointers.) There are no arrays of reference types in Java,
but only arrays of references.

Seems to me a case where arrays of pointers would be useful
in Fortran.

-- glen













glen herrmannsfeldt

unread,
Oct 1, 2015, 5:36:36 PM10/1/15
to
Wolfgang Kilian <kil...@invalid.com> wrote:

(snip)

> Sorry, but I'd say the code below illustrates the problem rather than
> solving it. First of all, you still need 9 versions to get all real and
> integer kinds. They are distributed in various SELECT TYPE clauses, and
> you will run into difficulties if a kind is absent for some compiler or
> two named kinds coincide.

> Second, you require the user to extend a base type SORTABLE. However,
> the user type will in general already be an extension of some base type.
> It is not good design to enforce a class hierarchy if the only purpose
> is adding a particular procedure.

This is the reason Java has interface. Java doesn't have multiple
inheritance, more or less for the reason you say. A class can only
have one parent, but can implement many interfaces. Many classes
implement Comparable, which allows them to be used by generic
sort methods.

-- glen

glen herrmannsfeldt

unread,
Oct 1, 2015, 5:39:40 PM10/1/15
to
Wolfgang Kilian <kil...@invalid.com> wrote:

(snip)

> The domain of Fortran is scientific/numeric programming. Leaving aside
> proprietary code, there are two other languages most frequently used in
> that area: C++ and Python. C++ is compiled and actually competitive
> with Fortran. Python is not competitive regarding efficiency, but
> accepted as 'convenient'.

Being an interpreted language, python can be slow.

But like most interpreted languages, once performing an operation,
it is about as fast.

For complicated scientific programming, you might do many matrix
operations on large matrices that could be about as fast.

-- glen

Ian Harvey

unread,
Oct 1, 2015, 6:07:44 PM10/1/15
to
On 2015-10-02 3:16 AM, Dan Nagle wrote:
> On 2015-09-30 19:50:03 +0000, FortranFan said:
...
>> 3. And what if one wants to combine multiple use cases and wants to
>> challenge the standards body to come up with a common solution that
>> takes all the use cases in mind which involves minimal syntactical
>> additions to the language? That was a motivating idea in the original
>> post for two use cases, for generic methods and generic containers.
>
> One can create a higher-rank array using any type in Fortran,
> so I think the generic containers argument is a bit weak.
> With the generic methods, what tasks are you trying to solve?

An array is just one form of container. Arrays have certain
characteristics that make them suitable for some use cases, but those
characteristics (or absence of other characteristics) make them
unsuitable for other use cases.

Consider things like use of a linked list, where you may not care about
the ability to index an element by its position, but want efficient
insertion and deletion of elements at any position in the array; or use
of a map of some sort, where you want to index an element by something
other than its integer position.

Even if you are using an array as the underlying container, there will
be supporting code that is common regardless of the type of the array.
Consider something like reading a array of unknown size from a file (or
building from some other data source). Because reallocation of an array
can be expensive, in order to reduce the number of reallocations one
approach to this is to read into a doubling buffer or similar (another
approach is to read into a linked list that gets flattened into an array
- so see above).


TYPE :: t
!...
END TYPE t

SUBROUTINE get_array_of_t(unit, initial_size, array)
INTEGER, INTENT(IN) :: unit
INTEGER, INTENT(IN) :: initial_size
TYPE(t), INTENT(OUT), ALLOCATABLE :: array(:)
INTEGER :: l
INTEGER :: iostat
TYPE(t), ALLOCATABLE :: tmp(:)

ALLOCATE(array(initial_size))
l = 0
DO
IF (l + 1 > SIZE(array)) THEN
! We've run out of space - grow the buffer.
ALLOCATE(tmp(SIZE(array) * 2))
tmp(:SIZE(array)) = array
CALL MOVE_ALLOC(tmp, array)
END IF

!vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
! Some operation that populates a single element,
! or advises us that there are no more elements,
! or advises us that things have gone bad.
READ (unit, "(DT)", IOSTAT=iostat) array(l+1)
IF (IS_IOSTAT_END(iostat)) EXIT ! We are done.
IF (iostat /= 0) THEN
! Some sort of failure.
DEALLOCATE(array)
RETURN
END IF
!^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

l = l + 1
END DO
array = array(:l)
END SUBROUTINE get_array_of_t

I've got code that looks like this several times in one of my projects.
Practically, bar the type and the bits in between !vvv and !^^^ (which
you could parameterise out into a procedure), it should be the same
code. It's often not, because I appear to like typing, in the process
making different logic mistakes in each variation.

(I could rewrite the above with less code if I read into a scalar and
then grew the array using an array constructor, but that is likely to be
far less performant, particularly given typical Fortran processor
implementations.)

One rather specific solution would be to extend Fortran IO in some way
to permit variable size arrays to be read from a file. But that then
doesn't deal with the cases where the incoming information is not
accessed via Fortran IO.

Ian Harvey

unread,
Oct 1, 2015, 8:30:00 PM10/1/15
to
I think having module instantiations with same parameters separate, but
procedure instantiations with same procedures common, counter-intuitive.
Programs are comprised of program units, and therefore modules, as
program units, naturally seem to me to be "more global" than procedures.
I accept that thinking may not be particularly rigorous!

You have specified above a requirement that there only be one name with
generic code. I think that effectively rules out things like partial
specialisation. Perhaps that is reasonable from a simplicity point of
view, but consider what people might want to do if there was more than
one procedure parameter and procedures with multiple arguments.

I think explicit instantiation of generic procedures, where the
programmer explicitly says "make an instance of this parameterised
procedure with these actual parameters", preferable to implicit
instantiation. Explicit instantiation may be more verbose, but it
removes a potential point of confusion around the programmers intent;
drastically simplifies the language if you do have the possibility of
partial specialisation, overloading and the like (those two previous
points collectively combine to facilitate relevant error messages for
client programmers when they invariably stuff things up); and offers a
consistent pathway to parameterisation around aspects other than type
and kind in the future.

use gen, only: foo
type(some_type) :: x
call foo(some_type)(x)
! ^^^^^^^^^

I think the capability for the instantiation to be done in the one place
in a scope ahead of later multiple points of use to be very desirable -
`procedure :: my_foo => foo(some_type)` or whatever. This may also tie
in to considerations around whether instantiations are considered the
same or different.

I admit my views are strongly influenced by my C++ programming, where I
can never remember for any sustained period of time the rules around
resolution of function overrides in the face of templates, partial
specialisation and implicit conversions, so I tend to be explicit there.
Perhaps this just indicates that I am a bad C++ programmer, perhaps I
just like typing.

FortranFan

unread,
Oct 2, 2015, 12:24:43 AM10/2/15
to
On Thursday, October 1, 2015 at 3:29:27 AM UTC-4, Arjen Markus wrote:

> ..
>
> I have been thinking about various solutions to the problem and it might make a nice article (as I have hinted at in private to Ian), but here is the one I kind-of like. No tricks involved (renaming or includes), just unlimited polymorphs. Caveat: not all compilers/versions of compilers can handle it:
> ..

The code as shown basically goes into an infinite loop in function named lower because of the overloaded operation of "<" with a procedure containing two unlimited polymorphic arguments. If one renames the defined operation to, say, .islessthan. and changes the two lines in quicksort procedure to use this name, then the code runs fine. I'm not convinced there is a compiler problem here; one just has to beware when one is dealing with unlimited polymorphism.

Separately, the abstract derived type "sortable" plays no role in the code as shown. The particular test program of only default integer and real arrays can be made to work with simpler code:

! quicksort.f90 --
! Implement a generic QUICKSORT
!
! default integer and real supported
!
module quicksort_def

implicit none

private

public :: quicksort

contains

recursive subroutine quicksort( array )

!.. argument list
class(*), intent(inout) :: array(:)

!.. local variables
integer :: i
integer :: j

i = 1
j = size(array)

select type ( array )

type is ( integer )

blk_i: block

integer :: v
integer :: tmp

include "i.f90"

end block blk_i

type is ( real )

blk_r: block

real :: v
real :: tmp

include "i.f90"

end block blk_r

class default

!.. appropriate action elided
! need concrete design of sortable type to make use of it

end select

if ( 1 < j ) then
call quicksort( array(1:j) )
end if
if ( i < size(array) ) then
call quicksort( array(i:) )
end if

return

end subroutine quicksort

end module quicksort_def

Include file "i.f90":
v = array((j+i)/2) ! Use the middle element

do
do while ( array(i) < v )
i = i + 1
end do
do while ( v < array(j) )
j = j - 1
end do

if ( i <= j ) then
tmp = array(i)
array(i) = array(j)
array(j) = tmp
i = i + 1
j = j - 1
end if

if ( i > j ) then
exit
end if
end do

program test_quicksort
! test program

use quicksort_def

implicit none

integer, dimension(10) :: int_array
real, dimension(10) :: real_array
integer :: i

do i = 1,size(int_array)
int_array(i) = 11 - i
real_array(i) = 11.0 - i
enddo

write(*,*) 'Sorting ...'
call quicksort( int_array )
call quicksort( real_array )

write(*,*) 'Result:'
write(*,'(i10)') int_array
write(*,'(f10.2)') real_array

stop

end program test_quicksort

Upon execution with gfortran,
Sorting ...
Result:
1
2
3
4
5
6
7
8
9
10
1.00
2.00
3.00
4.00
5.00
6.00
7.00
8.00
9.00
10.00

Process returned 0 (0x0) execution time : 0.031 s
Press any key to continue.

Nonetheless, this situation basically highlights the effort and limitations a Fortran coder has to go through to achieve a semblance of generics. The language needs to offer much better support for such needs.

Jos Bergervoet

unread,
Oct 2, 2015, 2:37:07 AM10/2/15
to
On 10/1/2015 11:33 PM, glen herrmannsfeldt wrote:
> Gary Scott <garyl...@sbcglobal.net> wrote:
..
> Seems to me a case where arrays of pointers would be useful
> in Fortran.

You can make them using a defined type containing a pointer
and then creating an array of that type.

It might be unwise to allow arrays of pointers directly, while
we already have the pointer arrays (which are in fact pointers
to an array, or slice) lest things could become obfuscated.

If we recall, for example, the full flexibility of Algol68, then
one may ask what is so good about having infinite choice between
[] int
ref [] int
[] ref int
ref [] ref int
[] ref ref int
...

Don't make the language too flexible.

--
Jos

Arjen Markus

unread,
Oct 2, 2015, 2:39:44 AM10/2/15
to
Op vrijdag 2 oktober 2015 06:24:43 UTC+2 schreef FortranFan:
> On Thursday, October 1, 2015 at 3:29:27 AM UTC-4, Arjen Markus wrote:

>
> The code as shown basically goes into an infinite loop in function named lower because of the overloaded operation of "<" with a procedure containing two unlimited polymorphic arguments. If one renames the defined operation to, say, .islessthan. and changes the two lines in quicksort procedure to use this name, then the code runs fine. I'm not convinced there is a compiler problem here; one just has to beware when one is dealing with unlimited polymorphism.
>

No, I do not agree: the polymorphism is resolved using the select type construct. That is the reason it is there.

> Separately, the abstract derived type "sortable" plays no role in the code as shown. The particular test program of only default integer and real arrays can be made to work with simpler code:

That was merely an illustration of how you could do it for derived types. I was too lazy to provide an actual implementation ;).

>
> Nonetheless, this situation basically highlights the effort and limitations a Fortran coder has to go through to achieve a semblance of generics. The language needs to offer much better support for such needs.

Oh, I agree with you and Wolfgang on this point. However, I also agree with Dan that we need some real-life use cases to show that this is indeed necessary. This discussion provides some pointers as to the pros and cons of the current facilities Fortran offers. And I think that - despite the efforts you must go through - it is not entirely bad. We need to get a clearer picture of what is needed. The mere fact that other languages have templates is not enough. We need to:
- Show how real-life situation can be benefit from some new feature (like the parametrised modules in this discussion).
- Show what Fortran's current features can do, as it is not always easy to find a convenient solution. I am thinking of a small catalogue of examples (like in my book).
- Show how the more or less unique features of Fortran can be put to good use.

Regards,

Arjen

paul.rich...@gmail.com

unread,
Oct 2, 2015, 4:54:50 AM10/2/15
to
Dear All,

I wonder if it would satisfy everyone if the intrinsic operators could operate on unlimited polymorphic objects?

This could be done relatively easily by having the vtables point to procedures that implement the operators. Each of these procedures would have to check that the operands are of the same type but would still be small enough to be inlined by optimizers.

In combination with recursive allocatable components (todo for gfortran :-( ), all the good things like sets, queues and the rest should be possible. Quicksort would look a lot simpler!

Cheers

Paul


Arjen Markus

unread,
Oct 2, 2015, 5:30:26 AM10/2/15
to
Op vrijdag 2 oktober 2015 10:54:50 UTC+2 schreef paul.rich...@gmail.com:
That is the main reason for the somewhat elaborate select type construct in my case. I do not know if that would solve other cases, but it would be a nice start IMHO.

But intrinsic types do not have a vtable associated with them, do they? Does that complicate your suggestion?

Regards,

Arjen

Wolfgang Kilian

unread,
Oct 2, 2015, 5:53:05 AM10/2/15
to
On 10/02/2015 10:54 AM, paul.rich...@gmail.com wrote:
> On Friday, 2 October 2015 08:39:44 UTC+2, Arjen Markus wrote:
>> Op vrijdag 2 oktober 2015 06:24:43 UTC+2 schreef FortranFan:
>>> On Thursday, October 1, 2015 at 3:29:27 AM UTC-4, Arjen Markus wrote:
>>
>>>
>>> The code as shown basically goes into an infinite loop in function named lower because of the overloaded operation of "<" with a procedure containing two unlimited polymorphic arguments. If one renames the defined operation to, say, .islessthan. and changes the two lines in quicksort procedure to use this name, then the code runs fine. I'm not convinced there is a compiler problem here; one just has to beware when one is dealing with unlimited polymorphism.
>>>
>>
>> No, I do not agree: the polymorphism is resolved using the select type construct. That is the reason it is there.
>>
>>> Separately, the abstract derived type "sortable" plays no role in the code as shown. The particular test program of only default integer and real arrays can be made to work with simpler code:
>>
>> That was merely an illustration of how you could do it for derived types. I was too lazy to provide an actual implementation ;).
>>
>>>
>>> Nonetheless, this situation basically highlights the effort and limitations a Fortran coder has to go through to achieve a semblance of generics. The language needs to offer much better support for such needs.
>>
>> Oh, I agree with you and Wolfgang on this point. However, I also agree with Dan that we need some real-life use cases to show that this is indeed necessary. This discussion provides some pointers as to the pros and cons of the current facilities Fortran offers. And I think that - despite the efforts you must go through - it is not entirely bad. We need to get a clearer picture of what is needed. The mere fact that other languages have templates is not enough. We need to:
>> - Show how real-life situation can be benefit from some new feature (like the parametrised modules in this discussion).

Yes. I also understand Dan's point. Nevertheless, this new direction
of language design, if taken, should also be seen from a broad
perspective. There is some danger to introduce small solutions that
quickly become obsolete again. Think of FORALL.

>> - Show what Fortran's current features can do, as it is not always easy to find a convenient solution. I am thinking of a small catalogue of examples (like in my book).

They can do everything, of course. Unlike communication issues (with
the OS etc.) that introduced dynamic allocation, C interop, coarrays in
the language, generic programming is nothing more than a matter of
convenience. It is a convenience that perfectly fits in a compiled
language and should make code more reusable, readable and maintainable
without sacrificing efficiency. Polymorphism is also a convenience, but
of a different kind, and technically resolved at runtime.

>> - Show how the more or less unique features of Fortran can be put to good use.
>>
>> Regards,
>>
>> Arjen
>
> Dear All,
>
> I wonder if it would satisfy everyone if the intrinsic operators could operate on unlimited polymorphic objects?
>
> This could be done relatively easily by having the vtables point to procedures that implement the operators. Each of these procedures would have to check that the operands are of the same type but would still be small enough to be inlined by optimizers.

I don't think so. The result of intrinsic operators depends on argument
type, so the result type would also become undefined? The number of
places where Fortran's type system can be cheated should be kept small
(see TRANSFER, C_PTR).

I see unlimited polymorphism as a last resort. I haven't yet found the
need to have this feature in the language, but I accept that there were
reasons. Maybe class(*) can be used in some context for the time being,
to be replaced by better solutions once they become available -
analogous to pointer arrays in Fortran 90.

> In combination with recursive allocatable components (todo for gfortran :-( ), all the good things like sets, queues and the rest should be possible. Quicksort would look a lot simpler!

Those are perfectly possible in current Fortran. It's just that I have
to recode them each time I need some of those patterns, or resort to
some class(*)/include/implicit/preprocessor hack to save some code lines.

> Cheers
>
> Paul
>
>
>

-- Wolfgang

FortranFan

unread,
Oct 2, 2015, 8:39:40 AM10/2/15
to
On Friday, October 2, 2015 at 2:39:44 AM UTC-4, Arjen Markus wrote:

> ..
> > The code as shown basically goes into an infinite loop in function named lower because of the overloaded operation of "<" with a procedure containing two unlimited polymorphic arguments. If one renames the defined operation to, say, .islessthan. and changes the two lines in quicksort procedure to use this name, then the code runs fine. I'm not convinced there is a compiler problem here; one just has to beware when one is dealing with unlimited polymorphism.
> >
>
> No, I do not agree: the polymorphism is resolved using the select type construct. That is the reason it is there.
>


Perhaps you can start another thread to discuss the standard vis-a-vis defined operation precedence relative to intrinsic, so that this thread doesn't get hijacked by this sidebar matter. It should come down to the standard - does it say explicitly say that when the types are intrinsic, intrinsic operator should get used? If yes, where? I don't recall seeing it as such, so it'll be helpful to know it. From what I remember (and may be I am wrong about this), don't the rules for procedure overloading, as described in the standard, effectively come down to the defined operation taking precedence over the intrinsic one? Below is a simpler test case for anyone who wants to follow up in conjunction with the standard, but PLEASE, PLEASE do so in a separate thread - let this be the last discussion on this matter in this thread. Thanks much,

module m

implicit none

private

interface operator(<)
module procedure lower
end interface operator(<)
public :: operator(<)

contains

function lower( op1, op2 ) result(islessthan)

!.. argument list
class(*), intent(in) :: op1, op2
!.. function result
logical :: islessthan

!.. local variables
integer :: in1
integer :: in2

print *, " enter lower: "
islessthan = .false.

select type (op1)

type is (integer)

in1 = op1
print *, " op 1 = ", in1

select type (op2)

type is (integer)

in2 = op2
print *, " op 2 = ", in2

islessthan = op1 < op2

end select

type is (real)

select type (op2)

type is (real)

islessthan = op1 < op2

end select

class default

!.. appropriate action elided

end select

end function lower

end module m
program p

use m, only : operator(<)

implicit none

logical :: islessthan

islessthan = ( 0 < 42 )
print *, " is 0 < 42? ", islessthan

stop

end program p

The above code works with gfortran, but Intel Fortran goes into an infinite loop as it applies the "<" operation recursively.

paul.rich...@gmail.com

unread,
Oct 2, 2015, 10:14:30 AM10/2/15
to
They do, once they have been associated with an unlimited polymorphic object. See http://code.woboq.org/gcc/gcc/fortran/class.c.html line 2483 onwards. You will see that, in addition to size and type information, there is already a pointer to a copy procedure.

>
> Regards,
>
> Arjen

I might just give it an experimental whirl.

Cheers

Paul

Thomas Koenig

unread,
Oct 3, 2015, 10:37:45 AM10/3/15
to
Wolfgang Kilian <kil...@invalid.com> schrieb:
> On 30.09.2015 17:12, Dan Nagle wrote:

>> The idea is to have applications programmers indicate
>> the problems, and the committee subgroups can resolve
>> the details of a proposed cure.

> In short, type-safe containers such as vector, stack, queue and the like
> make obvious use cases that would be immediately accepted by Fortran
> practitioners. Also think of generic tree structures.

Very much so.

At the moment, a Fortran programmer is forced to roll his own when
implementing standard computer science algorithms with containers
such as trees, linked lists etc.

A facility to allow to write such routines once, for any type,
would definitely be very useful, and I would certainly use it.

Richard Maine

unread,
Oct 3, 2015, 11:19:28 AM10/3/15
to
FortranFan <pare...@gmail.com> wrote:

> It should come down to the standard - does it say explicitly say that when
> the types are intrinsic, intrinsic operator should get used? If yes,
> where? I don't recall seeing it as such, so it'll be helpful to know
> it. From what I remember (and may be I am wrong about this), don't the
> rules for procedure overloading, as described in the standard,
> effectively come down to the defined operation taking precedence over
> the intrinsic one? Below is a simpler test case for anyone who wants to
> follow up in conjunction with the standard, but PLEASE, PLEASE do so in
> a separate thread - let this be the last discussion on this matter in
> this thread.

Quickly checking internet stuff in my Mom's appartment while here for a
visit, so it isn't handy for me to drag out citations (or to start a
separate hread, though I'll change to topc, which might have that
effect).

But my recollection is that there is a difference depending in whether
you are talking about functions versus operators. You can override an
intrinsic function with a user one; that is yes, if you have both, your
user one will take precedence. But you cannot override an intrinsic
operator. Applying + to 2 integers always means addition; you can't
change that. If you could change that, it would make life more confusing
than it is anyway.

--
Richard Maine
email: last name at domain . net
domain: summer-triangle

FortranFan

unread,
Oct 3, 2015, 11:21:06 AM10/3/15
to
On Saturday, October 3, 2015 at 10:37:45 AM UTC-4, Thomas Koenig wrote:

> ..
> Wolfgang Kilian <kil...@invalid.com> schrieb:
> ..
>
> > In short, type-safe containers such as vector, stack, queue and the like
> > make obvious use cases that would be immediately accepted by Fortran
> > practitioners. Also think of generic tree structures.
>
> Very much so.
>
> At the moment, a Fortran programmer is forced to roll his own when
> implementing standard computer science algorithms with containers
> such as trees, linked lists etc.
>
> A facility to allow to write such routines once, for any type,
> would definitely be very useful, and I would certainly use it.


Ultimately if the facility would extend to something "intrinsic derived type" from a new/existing intrinsic module, it may serve most Fortran programmers best:

-- begin pseudo code --

..
!.. Use std_list container type for list from intrinsic module
! iso_fortran_containers
use, intrinsic :: iso_fortran_containers, only : std_list
..
use foo_m, only : foo_t
..
type(foo_t) :: foo
..
!.. type specification syntax perhaps similar to parameterized derived
! types?
type(std_list(T=foo_t))) :: foo_list !.. a list of foo using standard list container

call foo_list%insert( pos=1, val=foo ) !.. insert an element at position 1
..

-- end pseudo code --

and so on for containers that scientific/engineering and other numerical computing applications use routinely using other languages such as C++/Java/C#, etc.

FortranFan

unread,
Oct 3, 2015, 11:30:42 AM10/3/15
to
On Saturday, October 3, 2015 at 11:19:28 AM UTC-4, Richard Maine wrote:
@Richard,

Thanks much for your response. Arjen Markus did start another thread on this discussion here:
https://groups.google.com/forum/#!topic/comp.lang.fortran/Ke-8-fOzXFQ

I've posted your comments on the above new thread, so whoever is following that will notice your comments.

By the way, I've posted a small subsection from the standard in the new thread, don't know if it is relevant. You'd know a lot better. I couldn't find in the standard what you say in terms of "you cannot override an intrinsic operator"

Perhaps this particular discussion can be continued in this other new thread?

Thanks,

William Clodius

unread,
Oct 4, 2015, 10:11:41 PM10/4/15
to
Dan Nagle <danl...@mac.com> wrote:

> <Snip>
> >
> > 3. And what if one wants to combine multiple use cases and wants to
> > challenge the standards body to come up with a common solution that
> > takes all the use cases in mind which involves minimal syntactical
> > additions to the language? That was a motivating idea in the original
> > post for two use cases, for generic methods and generic containers.
>
> One can create a higher-rank array using any type in Fortran,
> so I think the generic containers argument is a bit weak.
> With the generic methods, what tasks are you trying to solve?
> <snip>

A simplistic user defined growable array has access nominally to a
single independent of position, but array creation proportinal to n^2,
with more sophistication n log(n). Creation has the potential for memory
leaks, or residual memory gaps that the processor might have difficulty
exploiting. A linked list access in sequence the same as an array, but
expansion proportional to n. If you need access out of sequence then a
linked list is inappropriate.

A tree is generally accessed in a fixed sequence. It should be created
at a cost of n leaves.. Mapping it to a growable array results in a
potential creation cost of n^2 or n log(n) again, and writing the
mapping operations is error prone.

Hash table, queu, stack see above.

William Clodius

unread,
Oct 4, 2015, 10:30:16 PM10/4/15
to
Dan Nagle <danl...@mac.com> wrote:

> Hi,
>
> If you want to make some progress on this, develop
> a set of use-cases that generic programming should address.
>
> Background
>
> I've been trying to get WG5 and J3 to work on new revisions
> of the standard from use-cases rather than more-or-less
> completely developed new feature proposals. Hopefully, we will
> be able to pay some attention to questions of strategic direction
> rather than only details of specific proposals.
>
> The idea is to have applications programmers indicate
> the problems, and the committee subgroups can resolve
> the details of a proposed cure.
>
> I believe we can better serve the community by starting with use-cases.
> Applications programmers can say what their issues are, and
> compiler engineers can spot cases where the cost-benefit
> of the feature is wrong and design around them.
>
> If the only use-case for generic programming support is a sort routine,
> the proposal will have a hard time (cost-benefit will be seen
> as wrong due mainly to lack of benefit). Part of the exercise
> is to define goals and part of the exercise is to prioritize
> use of resources (mainly, compiler engineers' time).
>
> Example
>
> So I'll get the ball rolling . . .
>
> I want some help with the following problem:
>
> I have a file with a f77 library in it. I want to have a module
> that will support all routines in the library for all (or most) real kinds
> supported by several compilers. The compilers support different
> numbers of real kinds with different kind values. I don't want
> to force my users to recompile the module file every time it is used
> but I do want the user to be able to select any kind value desired.
> I do not want to use a macro preprocessor because that complicates
> the build process (and I may hand this project to someone else
> who may not have my priorities of software maintenance).

Dan:

Starting with last first:

------------------------------------------------

I'll assume the "following problem" is a separate issue not related to
generic types, but what you wrote in this contex confuses me F77
library and module and kind values is a confusing mix without also
introducing potential future use of generics. Dropping the generic
requirement simplifies things.

I expect you have avoided this problem, but be aware of the potential
combinational probems of mixing real kinds. If you have F(A,B) where A,
B, and F are REAL and you have three REAL kinds, then in principle there
can be 27 different versions of F if you allowed an arbitrary mix.
Normally most procedures either don't mix kinds, or keep some kinds
fixed and keeping the varying kinds the same. In either case for N kinds
of reals, there will be N procedures. In that case you only need N
libraries. I will assume that in what follows

In the current computing environment the vast majority of computers with
machine floating point are 8 bit byte addressing, with machine types
power of two multiples of 8 bits. The vast majority of those use some
form of IEEE floating point. I suspect the majority of floating point
systems without IEEE are dedicatied systems for historical applications
whose users would not be allowed to use your code, so I would encourage
you to focus on IEEE systems. I might be wrong, but I believe for IEEE
there are essentially four chice: single precision which is always
available, double which may always available, double extended on at
least some INTEL machines, and quad which is often available.

If, as I suspect, you only need one library for each supported kind, and
you can keep it down to at most four real IEEE kinds, with single and
double always supported, and only extended and quad as an option, then
you have four possible combinations of libraries:
Single double
single double extended
single double quad
single double extended quad
If my assumptions are not correct then the number of libraries can
increase rapidly, though in principle it can be handled using methods
similar to what I give below.

I would create separate module for each library. For the extended and
quad there will be two versions, with different names or locations one
to provide code and one empty. It would help if you could put each F77
library in a separate fixed format module, if not then I would provide
explicit interfaces for the procedures in each appropriate module. With
the explict interfaces you will want to ensure different names for each
procedure. The historic method of differentiating names was to have a
separate prefix (typically a single letter, e.g., s, d, x, and q) for
each kind. In the module headers I would then provide generic interfaces
for each of the modules procedures. I would then write a top level
modules, using the four library modules.

I would then create a fortran code to write out four text lines each
with the corresponding selected real kind for the corresponding
precision. If the file already exists it should read the file and see if
the values have changed, and only write the file if they have changed.
Make or its equivalent will always compile and run this code, if the
output has changed (presumably for the extended or quad library) then
depending on the direction of change the file representing the
appropriate library will be changed. this will result in a
recompilartion cascade if (andI believe only if) the compiler kinds
have changed.

------------------------------------------------

The most widely publicisized use of template is in the implementation of
generic structured types: lists, trees, hash tables, growable arrays,
etc. When I first encountered the British effort to develope
parameterized derived types for what became F2003, I decided that it was
a facility with most of the complications of templates, but no
capability of providing generic structured types. It felt like it had
less than 20% of the benefits. What you need is something with 90%+ of
the benefits of templates with not much more complication than
parameterized derived types.

One important aspect of generic structured types is that in many cases
they do not have significant state. If you need say, a "list" of integer
values in two different sections of code, you want to make it easy to do
so without generating two separate bodies of code. Further for
structures used in non critical portions of the code, it can be useful
to not have to have separate declarations for each instance of a
structure that differs only in the type of their components.

Structured types typically require not only a definition of the form of
the structure similar to derived types, but also procedures to
manipulate the structures. The naturals way to combine that
functionality in Fortran 90+ is to put all the definitions in a module.
I would therfore make the initial basis of "templates" a structure based
on that of a module.

example of a module with no state (must have no module variables, or
saved entities in procedures, or modify variables of other
modules/common blocks.

pure module generic_list(component)
type:: component

...
type list
type(list), pointer:: next => null()
type(component) :: value
end type list

contains

...

subroutine push( value, head )
type(component), intent(in) :: value
type(list), pointer :: head
type(list), pointer :: new_head

allocate(new_head)
new_head % value = value
new_head % next => head
head => new_head

return

end subroutine push

subroutine pop( value, head )
type(component), intent(out) :: value
type(list), pointer :: head
type(list), pointer :: new_head

if (.not. associated( head) ) goto 999
value = head % value
new_head => head % next
deallocate( head )
head => new_head

return

write(*,"('In POP HEAD is unassociated.')")
stop

end subroutine push
...

subroutine reverse( head )
type(list), intent(inout), pointer :: head
type(list), pointer :: current, next, prev

current => example
prev => null()
do while( associated( current ) )
next => current % next
current % next => prev
prev => current
current => next
end do
head => current

return
end subroutine reverse

...

end module generic_lst

module ...
use generic_list( type(real) ) : real_llst=>list
use generic_list( my_type ) : my_list !

type my_type note I assume my_list can be referenced before
definiton
....
end type my_type

glen herrmannsfeldt

unread,
Oct 5, 2015, 3:32:47 AM10/5/15
to
William Clodius <w.cl...@icloud.com> wrote:
> Dan Nagle <danl...@mac.com> wrote:

(snip)

>> If the only use-case for generic programming support is a sort routine,
>> the proposal will have a hard time (cost-benefit will be seen
>> as wrong due mainly to lack of benefit). Part of the exercise
>> is to define goals and part of the exercise is to prioritize
>> use of resources (mainly, compiler engineers' time).

(snip on generics)

> I expect you have avoided this problem, but be aware of the potential
> combinational probems of mixing real kinds. If you have F(A,B) where A,
> B, and F are REAL and you have three REAL kinds, then in principle there
> can be 27 different versions of F if you allowed an arbitrary mix.
> Normally most procedures either don't mix kinds, or keep some kinds
> fixed and keeping the varying kinds the same. In either case for N kinds
> of reals, there will be N procedures. In that case you only need N
> libraries. I will assume that in what follows

I suppose, but in the usual case the return type of a generic
function is defined in terms of its argument types. Otherwise,
you need some way to indicate the return type you want.

The previously mentioned C++ templates, as far as I can see,
all arguments are expected to be the same type.

It might be that some compilers will convert (remember call by value)
some arguments as appropriate.

Java doesn't have such templates, but its type conversion rules
often are helpful. If you write functions with all arguments of
the same types, the widening conversions will allow for mixed types.

> In the current computing environment the vast majority of computers with
> machine floating point are 8 bit byte addressing, with machine types
> power of two multiples of 8 bits. The vast majority of those use some
> form of IEEE floating point. I suspect the majority of floating point
> systems without IEEE are dedicatied systems for historical applications
> whose users would not be allowed to use your code, so I would encourage
> you to focus on IEEE systems. I might be wrong, but I believe for IEEE
> there are essentially four chice: single precision which is always
> available, double which may always available, double extended on at
> least some INTEL machines, and quad which is often available.

IEEE 754-2008 defines five basic formats, binary32, binary64,
binary 128, decimal64, and decimal128. Also, two non-basic
formats that might be used for storage but not computation.

> If, as I suspect, you only need one library for each supported kind, and
> you can keep it down to at most four real IEEE kinds, with single and
> double always supported, and only extended and quad as an option, then
> you have four possible combinations of libraries:
> Single double
> single double extended
> single double quad
> single double extended quad
> If my assumptions are not correct then the number of libraries can
> increase rapidly, though in principle it can be handled using methods
> similar to what I give below.

The standard allows for extended precision that aren't the basic
formats, but the interchange formats, ones that you might, for
example write to a disk file, are the basic formats above, plus
the binary16 and decimal32 format. It seems to suggest that
extended formats are not interchange formats.

Seems to me that extended formats, such as intel 80 bit, should
be used for intermediate values during computation, but not
for user variables, and not for function argument or return types.

It seems to be taking a long time for hardware, other than IBM
and VAX, to implement the 128 bit formats.

> I would create separate module for each library. For the extended and
> quad there will be two versions, with different names or locations one
> to provide code and one empty. It would help if you could put each F77
> library in a separate fixed format module, if not then I would provide
> explicit interfaces for the procedures in each appropriate module. With
> the explict interfaces you will want to ensure different names for each
> procedure. The historic method of differentiating names was to have a
> separate prefix (typically a single letter, e.g., s, d, x, and q) for
> each kind. In the module headers I would then provide generic interfaces
> for each of the modules procedures. I would then write a top level
> modules, using the four library modules.

> I would then create a fortran code to write out four text lines each
> with the corresponding selected real kind for the corresponding
> precision. If the file already exists it should read the file and see if
> the values have changed, and only write the file if they have changed.
> Make or its equivalent will always compile and run this code, if the
> output has changed (presumably for the extended or quad library) then
> depending on the direction of change the file representing the
> appropriate library will be changed. this will result in a
> recompilartion cascade if (andI believe only if) the compiler kinds
> have changed.

As I mentioned in other posts, sometimes the algorithm, or
parameters of it, will depend on the kind. That complicates
writing generic routines, but maybe not too much.

(snip)

> The most widely publicisized use of template is in the implementation of
> generic structured types: lists, trees, hash tables, growable arrays,
> etc. When I first encountered the British effort to develope
> parameterized derived types for what became F2003, I decided that it was
> a facility with most of the complications of templates, but no
> capability of providing generic structured types. It felt like it had
> less than 20% of the benefits. What you need is something with 90%+ of
> the benefits of templates with not much more complication than
> parameterized derived types.

Seems to me a different problem. Container types don't have
to look inside the types. Sort or search routines need a
compare routine, but the sort routine still doesn't need
to look inside.

But numeric generics will often need to look inside.

(snip)

-- glen

Ian Harvey

unread,
Oct 5, 2015, 4:51:03 AM10/5/15
to
On 2015-10-05 6:32 PM, glen herrmannsfeldt wrote:
...
> I suppose, but in the usual case the return type of a generic
> function is defined in terms of its argument types. Otherwise,
> you need some way to indicate the return type you want.
>
> The previously mentioned C++ templates, as far as I can see,
> all arguments are expected to be the same type.
>
> It might be that some compilers will convert (remember call by value)
> some arguments as appropriate.

It is up to the programmer.

tenplate <class T, class U, class V>
T some_function(U arg1, V arg2)
{
...
}

There are language rules around template argument deduction in the face
of implicit conversions of parameters.

...
>> The most widely publicisized use of template is in the implementation of
>> generic structured types: lists, trees, hash tables, growable arrays,
>> etc. When I first encountered the British effort to develope
>> parameterized derived types for what became F2003, I decided that it was
>> a facility with most of the complications of templates, but no
>> capability of providing generic structured types. It felt like it had
>> less than 20% of the benefits. What you need is something with 90%+ of
>> the benefits of templates with not much more complication than
>> parameterized derived types.
>
> Seems to me a different problem. Container types don't have
> to look inside the types. Sort or search routines need a
> compare routine, but the sort routine still doesn't need
> to look inside.
>
> But numeric generics will often need to look inside.

Some containers are "intrusive", in that there is interaction between
the nature of how the object is stored in a container and the value of
the object itself.

glen herrmannsfeldt

unread,
Oct 5, 2015, 6:04:35 AM10/5/15
to
Ian Harvey <ian_h...@bigpond.com> wrote:

(snip, I wrote)

>> I suppose, but in the usual case the return type of a generic
>> function is defined in terms of its argument types. Otherwise,
>> you need some way to indicate the return type you want.

>> The previously mentioned C++ templates, as far as I can see,
>> all arguments are expected to be the same type.

>> It might be that some compilers will convert (remember call by value)
>> some arguments as appropriate.

> It is up to the programmer.

> tenplate <class T, class U, class V>
> T some_function(U arg1, V arg2)
> {
> ...
> }

OK, but how does it know the type of T?

U and V are the types of the arguments, but not T.

I can see the case where the return type is the type of one
of the arguments.

How about the case where the return type must be wider than
the arguments, so two shorts returns int, two ints returns long?
How do you specify that?

> There are language rules around template argument deduction in the face
> of implicit conversions of parameters.

(snip)

-- glen

Ian Harvey

unread,
Oct 5, 2015, 6:15:56 AM10/5/15
to
On 2015-10-05 9:04 PM, glen herrmannsfeldt wrote:
> Ian Harvey <ian_h...@bigpond.com> wrote:
>
> (snip, I wrote)
>
>>> I suppose, but in the usual case the return type of a generic
>>> function is defined in terms of its argument types. Otherwise,
>>> you need some way to indicate the return type you want.
>
>>> The previously mentioned C++ templates, as far as I can see,
>>> all arguments are expected to be the same type.
>
>>> It might be that some compilers will convert (remember call by value)
>>> some arguments as appropriate.
>
>> It is up to the programmer.
>
>> tenplate <class T, class U, class V>
>> T some_function(U arg1, V arg2)
>> {
>> ...
>> }
>
> OK, but how does it know the type of T?
>
> U and V are the types of the arguments, but not T.
>
> I can see the case where the return type is the type of one
> of the arguments.
>
> How about the case where the return type must be wider than
> the arguments, so two shorts returns int, two ints returns long?
> How do you specify that?

The programmer explicitly specifies the type in source. The ability to
automatically deduce template parameters only applies to types used as
function parameters.

int x = some_function<int,float,double>(2.0f, 4.0);

(Don't ask too many more questions, or I'll just start demonstrating my
ignorance of the details.)

Thomas Koenig

unread,
Oct 5, 2015, 1:32:35 PM10/5/15
to
Ian Harvey <ian_h...@bigpond.com> schrieb:

> There are language rules around template argument deduction in the face
> of implicit conversions of parameters.

And this is one area where Fortran, which does not do implicit
conversion of actual arguments, has an advantage over C++.

Combining templates with type conversion is... horrible.

vladim...@gmail.com

unread,
Oct 8, 2015, 5:41:19 AM10/8/15
to

> Second, you require the user to extend a base type SORTABLE. However,
> the user type will in general already be an extension of some base type.
> It is not good design to enforce a class hierarchy if the only purpose
> is adding a particular procedure.
>
> I guess this is an obvious use case where only actual generic
> programming can resolve the issue in a satisfactory way.

I think this example illustrates, why Java style interfaces (https://en.wikipedia.org/wiki/Interface_%28Java%29) would be great alternative to multiple inheritance, which is a BAD THING(TM) for sure.


type, extends(my_parent), implements(sortable) :: my_type
...
end type

where implements(sortable) just means that the type must override the deferred type bound procedures

procedure(assign_object), deferred :: copy
procedure(one_lower_than_two), deferred :: lower

but there must not be any components defined by the "interface".

w.van....@gmail.com

unread,
Feb 4, 2016, 3:01:30 PM2/4/16
to
I proposed a facility similar to Ada generic packages several times. The most recent proposal is http://j3-fortran.org/doc/year/05/05-195.pdf. It has references to earlier proposals. It was briefly part of the 2008 work plan, but got superceded by a proposal for macros. The argument was that macros could do everything parameterized modules could do, and a few others. I consider the proposed syntax for macros to be ugly and confusing. Eventually macros were also deleted from the 2008 work plan because the perfect was the enemy of the good, that is, there were things that some people wanted them to do but that they couldn't do, so the baby got thrown out with the bath water.

William Clodius proposed something similar in http://j3-fortran.org/doc/year/97/97-118r1.txt.

In 2012 I developed http://j3-fortran.org/doc/year/12/12-176.txt, a stripped-down proposal for parametric subprograms, primarily to address the discontinuity between parameterized derived types and type-bound procedures. It was not considered for the 2015 work plan.

The problem isn't that the Fortran committees lack ideas to address the problem of generic programming. It's simply that the majority consider other work to be more important.

Jos Bergervoet

unread,
Feb 4, 2016, 4:37:12 PM2/4/16
to
On 9/29/2015 8:49 AM, Arjen Markus wrote:
> The code below was inspired by the module Jos Bergervoet posted.
> It defines a "cascade" of types with a single, generically defined operation.

This is of course the well-known the Cayley-Dickson construction
(If you refer to my "module Cayley_Dickson", that is. And a nice
description by John Baez is here:
<http://math.ucr.edu/home/baez/octonions/node5.html> )

--
Jos

K

unread,
Feb 4, 2016, 9:48:20 PM2/4/16
to
Le jeudi 4 février 2016 20:01:30 UTC, w.van....@gmail.com a écrit :
> I proposed a facility similar to Ada generic packages several times.
> The most recent proposal is http://j3-fortran.org/doc/year/05/05-195.pdf.
> It has references to earlier proposals. It was briefly part of the 2008
> work plan, but got superceded by a proposal for macros. The argument
> was that macros could do everything parameterized modules could do, and
> a few others. I consider the proposed syntax for macros to be ugly and
> confusing. Eventually macros were also deleted from the 2008 work plan
> because the perfect was the enemy of the good, that is, there were things
> that some people wanted them to do but that they couldn't do, so the baby
> got thrown out with the bath water.

I like parameterized modules. I also really like the idea of type parameters,
and I wish we had something like that for derived types. It might have solved
a lot of the problems we have because of the lack of generics.

But then, I also like the idea of parameterized derived type, derived-type
I/O and submodules, which are not the most popular features of F2003, judging
from the time they take to be implemented in compilers.

>
> William Clodius proposed something similar in
> http://j3-fortran.org/doc/year/97/97-118r1.txt.
>
> In 2012 I developed http://j3-fortran.org/doc/year/12/12-176.txt, a
> stripped-down proposal for parametric subprograms, primarily to address
> the discontinuity between parameterized derived types and type-bound
> procedures. It was not considered for the 2015 work plan.
>
> The problem isn't that the Fortran committees lack ideas to address the
> problem of generic programming. It's simply that the majority consider
> other work to be more important.

Even if a proposal is discussed right now (which isn't the case as far as I
know, but I would love to be wrong), it won't be in a standard before
whatever comes after F2015, and then won't be useable before the major
compilers implement it. And at the same time, we would not need a repeat of
what happened with FORALL (something that sounds great, but ends up being
very rarely used because of its limitations, and is obsolete two standards
later).

That said, I am really thankful for the work done by the committees members.
Even if nothing is ever perfect, F2003 and F2008 each contained very nice
features and improvements. So there is hope that something acceptable will be
found for generics.

Ian Harvey

unread,
Feb 5, 2016, 12:11:45 AM2/5/16
to
On 2016-02-05 7:01 AM, w.van....@gmail.com wrote:
> I proposed a facility similar to Ada generic packages several times.
> The most recent proposal is
> http://j3-fortran.org/doc/year/05/05-195.pdf. It has references to
> earlier proposals. It was briefly part of the 2008 work plan, but
> got superceded by a proposal for macros. The argument was that
> macros could do everything parameterized modules could do, and a few
> others. I consider the proposed syntax for macros to be ugly and
> confusing. Eventually macros were also deleted from the 2008 work
> plan because the perfect was the enemy of the good, that is, there
> were things that some people wanted them to do but that they couldn't
> do, so the baby got thrown out with the bath water.

Is there a document that describes the macro proposal?


Thomas Koenig

unread,
Feb 5, 2016, 2:26:31 AM2/5/16
to
K <kala...@me.com> schrieb:

> But then, I also like the idea of parameterized derived type, derived-type
> I/O and submodules, which are not the most popular features of F2003, judging
> from the time they take to be implemented in compilers.

PDTs and DTIO are very hard to implement.

Submodules are F2008, not F2003. At least for gfortran, they
were implemented very quickly.

As always: Volunteers are welcome :-)

robin....@gmail.com

unread,
Feb 5, 2016, 3:38:22 AM2/5/16
to
On Tuesday, September 29, 2015 at 10:47:01 PM UTC+10, Ian Chivers wrote:
> I think the major problem is the comparison with C++ and C#.
> I did a course where the people had a mixed background of
> Fortran, C++ and C#. There was an air of incredulity from the
> C++ and C# people when we covered generic programming in Fortran.
>
> Here is a generic quicksort in C++
>
> \begin{verbatim}
> template <class Type>
> void swap(Type array[],int i, int j)
> {
> Type tmp=array[i];
> array[i]=array[j];
> array[j]=tmp;
> }
>
> template <class Type>
> void quicksort( Type array[], int l, int r)
> {
> int i=l;
> int j=r;
> Type v=array[int((l+r)/2)];
> for (;;)
> {
> while (array[i] < v) i=i+1;
> while (v < array[j]) j=j-1;
> if (i<=j)
> { swap(array,i,j); i=i+1 ; j=j-1; }
> if (i>j) goto ended ;
> }
> ended: ;
> if (l<j) quicksort(array,l,j);
> if (i<r) quicksort(array,i,r);
> }
>
> template <class Type>
> void print(Type array[],int size)
> {
> cout << " [ " ;
> for (int ix=0;ix<size; ++ix)
> cout << array[ix] << " ";
> cout << "] \n";
> }
>
> #include <iostream>
> using namespace std;
> int main()
> {
> double da[] =
> {1.9,8.2,3.7,6.4,5.5,1.8,9.2,3.6,7.4,5.5};
> int ia[] = {1,10,2,9,3,8,4,7,6,5};
> int size=sizeof(da)/sizeof(double);
> cout << " Quicksort of double array is \n";
> quicksort(da,0,size-1);
> print(da,size);
> size=sizeof(ia)/sizeof(int);
> cout << " Quicksort of integer array is \n";
> quicksort(ia,0,size-1);
> print(ia,size);
> return(0);
> }
> \end{verbatim}
>
> Here is a generic quicksort in C#.
>
> \begin{verbatim}
> using System;
> public static class generic
> {
>
> public static void
> swap< Type > (Type[] array,int i, int j)
> {
> Type tmp=array[i];
> array[i]=array[j];
> array[j]=tmp;
> }
>
> public static void
> quicksort< Type > ( Type[] array, int l, int r)
> where Type : IComparable< Type >
> {
> int i=l;
> int j=r;
> Type v=array[(int)((l+r)/2)];
> for (;;)
> {
> while (array[i].CompareTo( v) < 0 ) i=i+1;
> while (v.CompareTo(array[j]) < 0) j=j-1;
> if (i<=j)
> { swap(array,i,j); i=i+1 ; j=j-1; }
> if (i>j) goto ended ;
> }
> ended: ;
> if (l<j) quicksort(array,l,j);
> if (i<r) quicksort(array,i,r);
> }
>
> public static void
> print< Type > (Type[] array,int size)
> {
> int i;
> int l;
> l=array.Length;
> for (i=0;i<l;i++)
> Console.WriteLine(array[i]);
> }
>
> public static int Main()
> {
> double[] da =
> {1.9,8.2,3.7,6.4,5.5,1.8,9.2,3.6,7.4,5.5};
> int[] ia = {1,10,2,9,3,8,4,7,6,5};
> int size;
> size=da.Length;
> Console.WriteLine("Original array");
> print(da,size);
> quicksort(da,0,size-1);
> Console.WriteLine("Sorted array");
> print(da,size);
> size=ia.Length;
> Console.WriteLine("Original array");
> print(ia,size);
> quicksort(ia,0,size-1);
> Console.WriteLine("Sorted array");
> print(ia,size);
> return(0);
> }
>
> }
> \end{verbatim}
>
>
> On 29/09/2015 12:03, Arjen Markus wrote:
> > Op dinsdag 29 september 2015 12:35:37 UTC+2 schreef glen herrmannsfeldt:
> >
> >>
> >> Depending on what you mean by generic programming, it isn't
> >> especially easy the way Fortran is usually compiled.
> >>
> >
> > Actually, that is a question that intrigues me. The current Fortran standard does facilitate quite a few things, but what are the features that are truly missing? Templates a la C++? But that can be emulated, even if not in a really elegant way.
> >
> > Regards,
> >
> > Arjen
> >

And the Fortran version?

K

unread,
Feb 5, 2016, 10:13:26 AM2/5/16
to
Le vendredi 5 février 2016 07:26:31 UTC, Thomas Koenig a écrit :
> K <kala...@me.com> schrieb:
>
> > But then, I also like the idea of parameterized derived type, derived-type
> > I/O and submodules, which are not the most popular features of F2003, judging
> > from the time they take to be implemented in compilers.
>
> PDTs and DTIO are very hard to implement.
>

I can only assume, I am really not good at C(++) and I won't even claim I understand the gfortran front-end. But I have not seen much demand for it either, and the commercial compilers are late for that too. I would expect them to react to demand much more quickly than gfortran.

> Submodules are F2008, not F2003. At least for gfortran, they
> were implemented very quickly.
>

Regardless, I was very happy to see them coming, I think they are a very useful thing to help with code design. Now I just need NAG to get them, too.

> As always: Volunteers are welcome :-)

I realise that it might have sounded a bit bitter, but that was not the intention. You (the gfortran developers) are doing a great job, and from my point of view, the Fortran community would be in a much, much worse shape without gfortran (and clf, for that matter). But I am realistic about how much free time I have, and my skills in C. I would be happy to give money so I was interested when Damian mentioned crowdfunding efforts, but I realise it is not necessarily what you need.

William Clodius

unread,
Feb 5, 2016, 9:41:32 PM2/5/16
to
<w.van....@gmail.com> wrote:

> I proposed a facility similar to Ada generic packages several times. The
> most recent proposal is http://j3-fortran.org/doc/year/05/05-195.pdf. It
> has references to earlier proposals. It was briefly part of the 2008 work
> plan, but got superceded by a proposal for macros. The argument was that
> macros could do everything parameterized modules could do, and a few
> others. I consider the proposed syntax for macros to be ugly and
> confusing. Eventually macros were also deleted from the 2008 work plan
> because the perfect was the enemy of the good, that is, there were things
> that some people wanted them to do but that they couldn't do, so the baby
> got thrown out with the bath water.
>
> William Clodius proposed something similar in
> http://j3-fortran.org/doc/year/97/97-118r1.txt.

It, of course, had the problem that it showed how parameterization could
be represented without doing enough to show how it would be useful.
0 new messages