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

Unlimited polymorphism vs regular polymorphism: any performance penalty?

724 views
Skip to first unread message

Noob

unread,
Apr 10, 2015, 5:45:18 PM4/10/15
to
Hi there,

I'm wondering whether or not using class(*) imply in any extra
performance penalty compared with class(foo) (which I'm calling
"regular" polymorphism). To be honest, I'm only guessing that
passing around polymorphic variables and the select type construct
imply in performance penalty.

I was about to finish implementing my (I'd call genuinely) generic
doubly-linked list (with sorting) and I realized it was actually
easy to make it a list of not only variables whose type is an
extension of a previously predetermined abstract derived type but
actually a list of also scalar variables of all intrinsic types,
if I use class(*) in the appropriate places.

(Well, actually, this opens the possibility of including data
which may not be proper finalized and lead to memory leak, right?
I'm working on that).

'Not sure it is a good idea but right now it can also hold data of
different types in different nodes and I've also created a rule to
sort the list when it is "heterogeneous".

So, any reason (from the point of view of performance or otherwise)
not to use class(*) when I'm already using polymorphism all around?

Thank you.

Ian Harvey

unread,
Apr 10, 2015, 8:32:21 PM4/10/15
to
On 2015-04-11 7:45 AM, Noob wrote:
...
> I'm wondering whether or not using class(*) imply in any extra
> performance penalty compared with class(foo) (which I'm calling
> "regular" polymorphism). To be honest, I'm only guessing that
> passing around polymorphic variables and the select type construct
> imply in performance penalty.
...
> So, any reason (from the point of view of performance or otherwise)
> not to use class(*) when I'm already using polymorphism all around?

Because my thoughts aren't clear this will perhaps be one of the less
coherent things I've written (which is saying something)...

My current inclination is to regard CLASS(*) largely as a dynamic-
universal-storage-mechanism - that is, I'm hypothetically executing some
code and I know I'm going to need to store something, but from the
perspective of the executing code I haven't got a fig what the declared
type of the thing might be.

When I have same idea of what might need to be stored, then I prefer
that the characteristics of the storage reflect what is known about the
things to be stored, via the declared type of the storage.

I think using CLASS(*) as a prop for compile time generic programming
(as I view it) should be avoided. In a generic programming situation,
you may not know when you *write* the code what the characteristics of
the things you will be working with will be, but you generally do know
more at the time the source code is turned into a program. Alternative
approaches to CLASS(*) should be used in this case.

With the language as it is, those approaches need to use INCLUDE tricks
and the like. This is unfortunate, but that's the way the language is.
As discussed in many threads over the last few years (and in current
threads), this is something that I would like to see improved in F202X.

My inclination above is motivated by a general principle that the closer
the description in source is to the thing that you are actually trying
to describe, the better. To justify this general principle I wave my
hands and say things like "clarity of code", "greater potential for
compile time detection of errors" and "greater potential for optimisation".

As a guideline (exceptions exist**), if you are working with polymorphic
objects and you have SELECT TYPE popping up in your code all the time,
then you should have a good look at the design of your types. Ideally,
where you want to have different code execute based on the dynamic type
of an object, then you should have a binding that is overridden
appropriately for the types involved.

Obviously unlimited polymorphic objects have no bindings - hence you
can't achieve this ideal.


** Those who deal in absolutes are ALWAYS wrong.

FortranFan

unread,
Apr 11, 2015, 12:15:50 AM4/11/15
to
Do you have a genuine need to hold a list of any type? Then class(*) indeed becomes a good option as shown in the anylist example in Modern Fortran Explained by Metcalf et al. The key aspect is to be able to true to one's program requirements and striving not to overdesign or optimize early.

Wolfgang Kilian

unread,
Apr 11, 2015, 1:51:23 AM4/11/15
to
While class(*) or class(some_base_type) make a polymorphic list
possible, it is somewhat difficult to extract objects from the list and
turn them into typed objects again without explictly copying them.
MOVE_ALLOC for extracting allocatables (or its equivalent code for
pointers) don't work inside a SELECT TYPE clause.

-- Wolfgang

Noob

unread,
Apr 11, 2015, 10:13:41 AM4/11/15
to
On 10/04/2015 21:32, Ian Harvey wrote:
> On 2015-04-11 7:45 AM, Noob wrote:
> ...
>> I'm wondering whether or not using class(*) imply in any extra
>> performance penalty compared with class(foo) (which I'm calling
>> "regular" polymorphism). To be honest, I'm only guessing that
>> passing around polymorphic variables and the select type construct
>> imply in performance penalty.
> ...
>> So, any reason (from the point of view of performance or otherwise)
>> not to use class(*) when I'm already using polymorphism all around?
>
> Because my thoughts aren't clear this will perhaps be one of the less
> coherent things I've written (which is saying something)...
>

Well, not to me. Your post was very much appreciated and it gave me
a lot to think about. Thank you.

Noob

unread,
Apr 11, 2015, 10:27:21 AM4/11/15
to
On 11/04/2015 01:15, FortranFan wrote:
> On Friday, April 10, 2015 at 5:45:18 PM UTC-4, Noob wrote:
>> Hi there,
>>
>> I'm wondering whether or not using class(*) imply in any extra
>> performance penalty compared with class(foo) (which I'm calling
>> "regular" polymorphism). To be honest, I'm only guessing that
>> passing around polymorphic variables and the select type construct
>> imply in performance penalty.
>>
>> I was about to finish implementing my (I'd call genuinely) generic
>> doubly-linked list (with sorting) and I realized it was actually
>> easy to make it a list of not only variables whose type is an
>> extension of a previously predetermined abstract derived type but
>> actually a list of also scalar variables of all intrinsic types,
>> if I use class(*) in the appropriate places.
>>
>> (Well, actually, this opens the possibility of including data
>> which may not be proper finalized and lead to memory leak, right?
>> I'm working on that).
>>
>> 'Not sure it is a good idea but right now it can also hold data of
>> different types in different nodes and I've also created a rule to
>> sort the list when it is "heterogeneous".
>>
>> So, any reason (from the point of view of performance or otherwise)
>> not to use class(*) when I'm already using polymorphism all around?
>>
>> Thank you.
>
>
> Do you have a genuine need to hold a list of any type?

Not really. Right now, in my stuff I use only a single list, so I
declare the node data to have a specific type.

Since it required me some effort to have it working in a way it sort of
mimics C++ std::list, I thought it was a good idea to share it as a
FOSS. The challenge still is how to make it a possible list of
anything people may want. The answers I received here showed me that
using polymorphism for that may not be the way to go. Maybe using macros
is not such a bad idea, after I figure how to do it.

Cheers.

Noob

unread,
Apr 11, 2015, 10:45:09 AM4/11/15
to
I haven't thought about that. I think with pointers it is less
troublesome. What I was doing is like this

program test
implicit none

type :: mytype_t
integer :: i
end type

type(mytype_t), target :: foo_a
type(mytype_t), pointer :: foo_b
class(*), pointer :: foo_c

foo_a = mytype_t(5)
foo_c => foo_a

select type ( foo_c )
type is ( mytype_t )
foo_b => foo_c
end select

nullify(foo_c)

print*,foo_b%i

end program

Prints 5

With allocatables I really don't know how to do it.


Noob

unread,
Apr 11, 2015, 10:47:59 AM4/11/15
to
Umm, bad MWE. Please ignore it!

GianLuigi Piacentini

unread,
Apr 11, 2015, 1:47:08 PM4/11/15
to
Ian Harvey wrote:

> On 2015-04-11 7:45 AM, Noob wrote:
> ...
>> I'm wondering whether or not using class(*) imply in any extra
>> performance penalty compared with class(foo) (which I'm calling
>> "regular" polymorphism). To be honest, I'm only guessing that
>> passing around polymorphic variables and the select type construct
>> imply in performance penalty.
> ...
>> So, any reason (from the point of view of performance or otherwise)
>> not to use class(*) when I'm already using polymorphism all around?
>
> Because my thoughts aren't clear this will perhaps be one of the less
> coherent things I've written (which is saying something)...
>
> My current inclination is to regard CLASS(*) largely as a dynamic-
> universal-storage-mechanism - that is, I'm hypothetically executing some
> code and I know I'm going to need to store something, but from the
> perspective of the executing code I haven't got a fig what the declared
> type of the thing might be.
>
> When I have same idea of what might need to be stored, then I prefer
> that the characteristics of the storage reflect what is known about the
> things to be stored, via the declared type of the storage.
>
I'm just an hobbyst now, so it's only my 2 cents...

I like using precompiled libraries, and a container written in terms of
CLASS(*), in my limited experience, it useful as a precompiled library item,
too. It does not need any adaptation to store anything, so you have a
(hopefully) well defined API and you use that container as a black-box,
whatever you need to 'contain'. Retrieval needs a SELECT TYPE construct in
the container using code, though. This clutters the using side of the code.
If I know that I would store a well defined TYPE, I could prepare a
'retrieve_this_type' wrapper, hiding that SELECT TYPE.

By-the-way, all I do does not have to be particularly performant and is not
really complicated, so I can forget about optimization issues.

Gigi

Noob

unread,
Apr 11, 2015, 3:25:28 PM4/11/15
to
Have you written your own container classes this way?

From my uderstanding, a variable declared as CLASS(*) can be the target
of any pointer with declared type. So, a getter method of the form
list%Get_data( pos, data ), will give you a pointer "data" with data
declared as CLASS(*) that can be subsequently pointed-to without a
SELECT TYPE. From what I can see now, the major difficulty would be to
properly "finalize" list nodes when the data they hold contain pointers
used to allocate memory. Looks like it means that if your list only
holds data of the same type at a time, you don't even need a
"retrieve_this_type wrapper", if you guarantee that the pointer
association makes sense.

Am I right here?

Ian Harvey

unread,
Apr 11, 2015, 4:31:18 PM4/11/15
to
On 2015-04-12 5:25 AM, Noob wrote:
...
> From my uderstanding, a variable declared as CLASS(*) can be the target
> of any pointer with declared type. So, a getter method of the form
> list%Get_data( pos, data ), will give you a pointer "data" with data
> declared as CLASS(*) that can be subsequently pointed-to without a
> SELECT TYPE. From what I can see now, the major difficulty would be to
> properly "finalize" list nodes when the data they hold contain pointers
> used to allocate memory. Looks like it means that if your list only
> holds data of the same type at a time, you don't even need a
> "retrieve_this_type wrapper", if you guarantee that the pointer
> association makes sense.
>
> Am I right here?

In the general case, an object of declared type CLASS(*) can only be
pointed at by pointers of CLASS(*). An exception exists for pointers of
sequence type or type with the BIND(C) attribute.

As in your example posted else-thread, you can SELECT TYPE on an object
of CLASS(*) that has the target type and then point something of the
appropriate type at the associate name.

Note that there is a restriction on pointer and allocatable dummy
arguments that requires a match in declared type with the actual dummy
argument.

I don't see the immediate concern with finalization. CLASS(*) objects
that have finalizers in their dynamic type are finalized like other objects.

Noob

unread,
Apr 11, 2015, 5:04:29 PM4/11/15
to
Pointed _at_, yes. Sorry.

Is this non-conforming or even undefined behaviour?

module mycontainer_mod

type :: mycontainer_t
class(*), pointer :: data
contains
procedure, pass :: Copy_data
procedure, pass :: Get_data
end type

contains

subroutine Copy_data ( this, data )
implicit none
class(mycontainer_t), intent(inout) :: this
class(*), intent(in) :: data

allocate ( this%data, source = data )

end subroutine

subroutine Get_data ( this, data )
implicit none
class(mycontainer_t), intent(in), target :: this
class(*), intent(out), pointer :: data

data => this%data

end subroutine

end module

program test
use mycontainer_mod
implicit none

type :: mytype_t
integer :: i
character(len=1) :: a
end type

type(mycontainer_t) :: foo_a
type(mytype_t), pointer :: data_typed
class(*), pointer :: data_unlim

call foo_a%Copy_data ( mytype_t(5,"a") )

call foo_a%Get_data ( data_unlim )
data_typed => data_unlim

print*, data_typed%i, data_typed%a

end program

Prints
5 a

Thanks.

Ian Harvey

unread,
Apr 11, 2015, 8:12:05 PM4/11/15
to
On 2015-04-12 7:04 AM, Noob wrote:
> On 11/04/2015 17:31, Ian Harvey wrote:
>> In the general case, an object of declared type CLASS(*) can only be
>> pointed at by pointers of CLASS(*). An exception exists for pointers of
>> sequence type or type with the BIND(C) attribute.
...
> Pointed _at_, yes. Sorry.
>
> Is this non-conforming or even undefined behaviour?

See below.
This statement violates constraint C715 in F2008 (C717 in F2003, C716 in
current F201X draft) - "If /data-target/ is unlimited polymorphic,
/data-pointer-object/ shall be unlimited polymorphic, or of a type with
the BIND attribute or the SEQUENCE attribute."

Current and beta ifort don't appear to diagnose this constraint violation.

Noob

unread,
Apr 11, 2015, 9:14:25 PM4/11/15
to
I see. I had in mind an example from the book and the words "valid when
the dynamic type matches". It just happens that the example has
precisely a pointer of a type declared with BIND(C) at the LHS. Good
thing I was already using SELECT TYPE all the time.

The rule is crystal clear, though. (So is the book. I should've checked
before posting).

Thank you.




GianLuigi Piacentini

unread,
Apr 11, 2015, 9:44:18 PM4/11/15
to
Noob wrote:

> ...
>
> Have you written your own container classes this way?
>
Yes, a ring container (doubly linked list with tail linked to head). Still
work in progress. Never used in 'real' code. Example/test code seemed to
work. If I remember well, I also wrote a stack container using that ring as
backbone, seemed to work, too.
I put development in hold, because I changed interest (a rather frequent
happening - remember, I'm an hobbyst, now).

Basically, I realized that I have to store very few (~10) elements of the
same TYPE in a Set container. So, ended in using in 'real' code (some stuff
I'm using to help wife's work) an array-based and very naive - O(n*n) -
implementation, that I specialize by text-replacing a 'generic' TYPE to the
TYPE actually required - a sort of macro , or perhaps poor man template - I
do not have experience of it. But I have completely lost the library
approach. I have to edit code (albeit a very simple text replacement, plus
some minor coding: assign, destroy, test for ==, test for >) to 'specialize'
the implementation to the required TYPE.

gigi

Stefano Zaghi

unread,
Apr 12, 2015, 3:53:01 AM4/12/15
to
This is a very bad news!

In the last year I have strongly used a typed pointer to point an unlimited polymorphic one... with intel 14.x I always check if my code is standard (std03) and no warnings were printed...

For example I have a generic tree container like this https://github.com/szaghi/OFF/blob/testing/src/Data_Type_Tree.f90#L210 that I routinely use as in https://github.com/szaghi/OFF/blob/testing/src/Data_Type_Global.f90#L130 and all works very well... This is a very big issue if I have to modify this kind pointers.

There are any chances that the next standard allows typed pointers to point unlimited polymorphic pointers?

Ian Harvey

unread,
Apr 12, 2015, 7:48:30 AM4/12/15
to
(The same constraint is in the current draft for 201X, so if that's what
you mean by next standard, then I think the chance is very small.)

For my part - I hope not. In a statically typed language like Fortran,
the type system is there to help and protect the programmer from silly
mistakes. I don't think watering down that protection any further (I
don't even like the exemption for BIND(C) and sequence types) is a good
idea.

You need to bracket your pointer assignments with a select type
construct if you want your code to be portable.

I expect the absence of a diagnostic for that constraint violation is
just an oversight by the vendor of your compiler. I doubt that is an
intended extension.

Again, I do not think that CLASS(*) is really appropriate for generic
programming like this. If you know at compile time what the type of
items in your tree are always going to be, then, if practical, specify
that type at compile time. But note "if practical", and I accept that
the alternatives to CLASS(*) currently have their own issues.

Stefano Zaghi

unread,
Apr 12, 2015, 11:23:01 AM4/12/15
to
No, I disagree.

I use such a tree container for many types, not for just the one I linked. If I had to do it at compile time, I will have to write many trees... this generic programming is pratical and useful. If the standard dictacts that I have to trap all uses of these pointers into a select type I will do it, but I think that this choice is not practical, it is simply an addition of verbosity to language. If I point a wrong type with respect the one I previously stored I will have a runtime error, this is enough for me, I do not need a compile error

Richard Maine

unread,
Apr 12, 2015, 11:58:12 AM4/12/15
to
Stefano Zaghi <stefan...@gmail.com> wrote:
[about using unlimitted polymorphism]
I think you are overlooking the ways inheritance is typically applied to
this sort of thing. Just polymorphism alone doesn't get you much of
anywhere. You write your tree code with an extensible type, say
tree_type. Then if you want to use the tree with some_other_type, you
define

type, extends(tree_type) :: some_other_type_tree
type(some_other_type) :: the_data
end type

No replication of code involved.

It's been to long since I looked at this stuff (and I never actually did
it in production code because I retired before f2003 compilers were
widely available), but I vaguely recall that there are also ways that
involve using type embedding instead of inheritance. I'm afraid the
details other than the term escape me. Maybe after I'm more awake.:-)

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

Stefano Zaghi

unread,
Apr 12, 2015, 1:54:06 PM4/12/15
to
Dear Richard,

Maybe I have overlooked somethings, but my intentions were just to not define different trees at all (I need only one type of tree...), I was not trying to exploit inerithance. My aim was to define a generic container with some special behaviour. It works great until now.

You are right, I can define an abstract type and then extends it (indeed I do this for my generic file on the same project I have linked) and then define as many trees as I like, but with my present generic container I can totally avoid such a step. It seems to me that this a "religious" question against generic programming...

My best regards

Wolfgang Kilian

unread,
Apr 12, 2015, 3:23:53 PM4/12/15
to
On 04/12/2015 05:22 PM, Stefano Zaghi wrote:
> No, I disagree.
>
> I use such a tree container for many types, not for just the one I linked. If I had to do it at compile time, I will have to write many trees... this generic programming is pratical and useful. If the standard dictacts that I have to trap all uses of these pointers into a select type I will do it, but I think that this choice is not practical, it is simply an addition of verbosity to language. If I point a wrong type with respect the one I previously stored I will have a runtime error, this is enough for me, I do not need a compile error
>

Polymorphism can serve as an emulation for generic programming, as you
show - but I understand a list of class(*) items as a list of objects of
heterogeneous type. Many applications involve a list of objects of
uniform type - the heterogeneous list can do this, but all type checks
(explicit type casting during packing and unpacking) are done at
runtime. Also, pointers are required for purely technical reasons, even
if allocatables (MOVE_ALLOC) would be preferred.

Genuine generic list code would imply type safety and uniformity checked
at compile time and no penalty at runtime. Unfortunately, this is not
available in present Fortran. We just have a choice between duplicating
code, include tricks, C-pointer magic, macros, emulating generic code
via polymorphic code, or waiting until 202X.

-- Wolfgang

FortranFan

unread,
Apr 12, 2015, 3:36:23 PM4/12/15
to
On Sunday, April 12, 2015 at 1:54:06 PM UTC-4, Stefano Zaghi wrote:

> ... It seems to me that this a "religious" question against generic programming...
>

I don't know about "religious", but it is definitely fundamental.

Current support for generic programming in Fortran is inadequate.

Many programming areas (including STEM and HPC fields where Fortran does see continued use) can do with all kinds of container "classes" - lists, collections, stacks, hashsets, queues, etc., especially if the coders are developing/improving algorithms with OO design principles (c.f. Scientific Software Design: The Object-Oriented Way by Rouson et al.) Not only it is not straightforward at all to "roll" one's own classes using generics using standard Fortran at present, I think it is probably not a good place for Fortran either to not consider offering a standard library of such container classes so coders don't have to reinvent their own wheels.

Perhaps if "modern Fortran" with OOP features from Fortran 2003 onward get increasing applications and calls for generics become louder and more frequent, the standards committee(s) will start to pay more attention and good things may happen. Ok, it's just me pipe-dreaming! :-)

Ian Harvey

unread,
Apr 12, 2015, 4:41:11 PM4/12/15
to
Depending on details, note that you only need maybe a dozen lines of
extra source code per type specific tree.

This:

https://dl.dropboxusercontent.com/u/72287920/rbtree.zip

is an example for a red-black tree, which I adapted from an adaptation
by another Fortran programmer posting on the Intel forum, who adapted it
from the literate programming site. It uses a single INCLUDE to bring
an otherwise identical token sequence in as the body of a module that
provides the type specific tree type. I used a single INCLUDE for
packaging convenience, but it would probably be more efficient and
adaptable, source wise, if 1I had split it into two INCLUDE's - one for
the specification part fragment and one for the supporting subprogram
fragment.

This is the same approach used for the linked list data structure in the
FLIBS collection (http://flibs.sourceforge.net/linked_list.html).

INCLUDE is a certainly bit of a hack and this approach has its own
issues, but I think a dozen lines of code or so once per type to ensure
compile time type safety (and probable performance benefits) a pretty
compelling investment.

(With the above example I was experimenting with different ways of
implementing the internals of the tree, just to see how it "felt" from a
source code authoring point of view. As you may see, it would seem that
I need to increase the dose of the medication I am taking to overcome my
habitual over-use of user defined operators. Better low level
implementations will exist, but the packaging method using INCLUDE
discussed above should still be applicable.)

Other approaches are available that use means outside of the language
standard - such as the C preprocessor or some other templating
preprocessor. These other means usually offer greater capability and
flexibility, but with the cost of moving outside of standard support.

(I would like to see aspects of the capability offered by the INCLUDE
approach, and these other out-of-standard approaches, supported by the
base language, but NOT just by means of some dumb text replacement
method - I want to be able to articulate to the processor in source the
requirements that I have for the types and procedures that my generic
source operates on, so that the processor can assist me with compile
time diagnostics when I stuff things up.)

Noob

unread,
Apr 12, 2015, 8:52:04 PM4/12/15
to
ummm

I'm already dreaming of Fortran 202x.

By then I'll have children. The eldest will be a girl. I'll teach her
"The Way of Fortran", so she stays away from silly things like boys. By
the end of the decade she'll be a teenager and we'll have /that/
conversation after she comes with a strange talk about polymorphism and
generics or other controversial things. "Everyone is using!", she'll
say. I'll tell her "I don't understand. Why?", and she'll yell things
like "you never give me what I want. I need space... and templates".
Heartbroken, I'll shoot: "I work hard to make this family happy. Don't
you understand how much a Fortran 202x-compliant compiler costs? Look
around. Does it look like we can afford a Cray supercomputer?"

But I'll get things right with the younger, a boy. His first bedtime
book will be "/Moderner/ Fortran Explained. (Now with illustrations!)"

:-)




Stefano Zaghi

unread,
Apr 13, 2015, 12:45:17 AM4/13/15
to
<<<I don't know about "religious", but it is definitely fundamental.

Current support for generic programming in Fortran is inadequate. >>>

Dear Fortranfan, I am sorry I was not clear. I think that if we say that support for generic programming is inadequate we conflict with a "dogmatic" view of Fortran where OOP is seen as a marginal thing, a poor brother: the most part of fortran programers say "Fortran can do this in this manner... you do not need OOP". Indeed, I do not thing that support for generic programming is inadequare: maybe I am a fortran fan more than you, but I think that it is currently adequate, just unflexible but good (I accept any compromise because Fortran does its job well, translate formulas at the best). In this specif case I just think that trapping all usages of plomyrmphic pointers into a select type consitutes only an addiction of verbosity, not a real advantage.


<<<Many programming areas (including STEM and HPC fields where Fortran does see continued use) can do with all kinds of container "classes" - lists, collections, stacks, hashsets, queues, etc., especially if the coders are developing/improving algorithms with OO design principles (c.f. Scientific Software Design: The Object-Oriented Way by Rouson et al.) Not only it is not straightforward at all to "roll" one's own classes using generics using standard Fortran at present, I think it is probably not a good place for Fortran either to not consider offering a standard library of such container classes so coders don't have to reinvent their own wheels>>>

This was just my intention: a(n) (oc)tree container as could be an array, a list, a stack...(do you have many "types" of array as your variables?). For example Python has many of such containers defined as built-in or via standard libraries. I think that Fortran comitee can take inspirantion from Python (and others) and standardize such things: as you say, present fortran programmers should reinvent the wheel any time they want such a contanier.

<<<
Perhaps if "modern Fortran" with OOP features from Fortran 2003 onward get increasing applications and calls for generics become louder and more frequent, the standards committee(s) will start to pay more attention and good things may happen. Ok, it's just me pipe-dreaming! :-) >>>

I hope.

Dear Ian, thank you for replay.

<<<
Depending on details, note that you only need maybe a dozen lines of
extra source code per type specific tree.

This:

https://dl.dropboxusercontent.com/u/72287920/rbtree.zip

is an example for a red-black tree, which I adapted from an adaptation
by another Fortran programmer posting on the Intel forum, who adapted it
from the literate programming site. It uses a single INCLUDE to bring
an otherwise identical token sequence in as the body of a module that
provides the type specific tree type. I used a single INCLUDE for
packaging convenience, but it would probably be more efficient and
adaptable, source wise, if 1I had split it into two INCLUDE's - one for
the specification part fragment and one for the supporting subprogram
fragment.

...

INCLUDE is a certainly bit of a hack and this approach has its own
issues, but I think a dozen lines of code or so once per type to ensure
compile time type safety (and probable performance benefits) a pretty
compelling investment.
>>>

I know many tricks, such as inerithance from an absract type (https://github.com/szaghi/OFF/blob/testing/src/Data_Type_File_Base.f90#L47), include (https://github.com/szaghi/OFF/blob/testing/src/Data_Type_Vector.f90#L79) and so on. The question is not how many lines of code are saved by one trick with respect another. I do not like to use a trick at all. The question is why we cannot exploit the power of unlimited polymorfic class via standard code, but we need tricks...

Indeed, to make standard for my codes I have only to catch all pointers associated to an unlimited polymorphic class into a select type, but this add a lot of verbosity...

For the Fortran GURU, what is wrong with the following pseudo code?

type foo::
class(*), pointer:: d ! A data
endtype foo
type(foo):: container
integer:: i
allocate(container%d,source=3)
i => container%d
print "(I5)", i

In case the data stored is not an integer I will get a runtime error, that I think is enough. To make this standard I have to write:

type foo::
class(*), pointer:: d ! A data
endtype foo
type(foo):: container
class(*):: i
allocate(container%d,source=3)
i => container%d
select type(i)
type is(integer)
print "(I5)", i
end select

I found this more verbose without any relevant advantage.

<<<
I want to be able to articulate to the processor in source the
requirements that I have for the types and procedures that my generic
source operates on, so that the processor can assist me with compile
time diagnostics when I stuff things up.) >>>

Me too.

Wolfgang Kilian

unread,
Apr 13, 2015, 2:47:02 AM4/13/15
to
Although I'm sometimes inclined to adopt CLASS(*) stuff as a workaround
for some restricted but frequent use cases (until recently, compiler
support was insufficient anyway), I'd prefer the second version if given
a choice. The approach of the first version suspiciously reminds me of
F77 (lack of) interface checking.

That said, there are legions of programmers who can write structured and
maintainable code with Javascript, who don't care at all about strong
typing. Nevertheless, I don't like to give up what was already achieved
with Fortran. Regarding generic programming, I might adopt Ian's
approach with include, or abuse a macro processor, just to keep type
safety as a matter of principle. It looks like I'm becoming old-school:

> <<<
> I want to be able to articulate to the processor in source the
> requirements that I have for the types and procedures that my generic
> source operates on, so that the processor can assist me with compile
> time diagnostics when I stuff things up.) >>>
>
> Me too.
>

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

Stefano Zaghi

unread,
Apr 13, 2015, 3:49:26 AM4/13/15
to
Dear Wolfgang, I agree with at least in some points.

> Although I'm sometimes inclined to adopt CLASS(*) stuff as a workaround
> for some restricted but frequent use cases (until recently, compiler
> support was insufficient anyway), I'd prefer the second version if given
> a choice. The approach of the first version suspiciously reminds me of
> F77 (lack of) interface checking.

You are right, the first version has not an interface checking: it is compromise, I think that when working with polymorphic variables some Fortran constrains can be relaxed (I try to explain with more details in the following).

> That said, there are legions of programmers who can write structured and
> maintainable code with Javascript, who don't care at all about strong
> typing. Nevertheless, I don't like to give up what was already achieved
> with Fortran.

It is true. Anyhow, I love strong typing of Fortran just because this allows Fortran to be one of the fastest language, I will never try to implement a "crunching numbers machine" in javascript if I can use Fortran. I think that there is the possibility to save the best of Fortran (and strong typing is one the features to be saved) and, in the meanwhile, to integrate many useful feature of other languages.

> Regarding generic programming, I might adopt Ian's
> approach with include, or abuse a macro processor, just to keep type
> safety as a matter of principle. It looks like I'm becoming old-school:

I prefer clean, standard way for a sane generic programming, but I do not hate macro preprocessing (https://github.com/szaghi/PreForM).

If some of the Fortran comitee members are reading this thread, I would like to highlight that there is (sometimes) the "desire" to have the possibility to relax some Fortran constrains in flavor or "easy programming".

If I need to perform some computations with the highest efficiency possible I will use an array, but the "efficiency" (or the most important feature of a type) can be defined accordingly other parameters.

In many situations, where the computation speed is not crucial, it would be helpful to have a container like a "Python list" that is surely less efficient than an array, but it has other advantages.

Presently, if a Fortran programmer want a generic list (tree, stack...) must reinvent the wheel, use trick, (ab)use of macros and so on. I think that if Fortran will give the programmer the possibility to make a conscious choice between different built-in types there will not lack of efficiency: the programmer will use array for speed, unlimited polymorphic list for "minor" stuff. If will accept the compromise to not have an interface or compile time check or the highest efficiency for such a container, it the container has other features, e.g. easy to use, less verbose, flexible...

As it was for deferred allocatable character variables, a sort of "built-in" generic list would be very appreciated.

This is just an opinion of a "poor Fortran programmer", not the one of a nerd-hacker, thus I can completely wrong.

My best regards,

Stefano

FortranFan

unread,
Apr 13, 2015, 10:50:00 AM4/13/15
to
On Monday, April 13, 2015 at 12:45:17 AM UTC-4, Stefano Zaghi wrote:

> ..Fortran where OOP is seen as a marginal thing, a poor brother ... Indeed, I do not thing that support for generic programming is inadequare: maybe I am a fortran fan more than you, but I think that it is currently adequate, just unflexible but good (I accept any compromise because Fortran does its job well, translate formulas at the best). In this specif case I just think that trapping all usages of plomyrmphic pointers into a select type consitutes only an addiction of verbosity, not a real advantage.
>

It's a long time away, if all, that Fortran can genuinely be included on a page like this (http://en.wikipedia.org/wiki/Generic_programming#Programming_language_support_for_genericity).

Until then, I'll maintain the language is deficient in this important aspect of OOP.


>
> .. present fortran programmers should reinvent the wheel any time they want such a contanier.
>

Ergo a deficieny!

Stefano Zaghi

unread,
Apr 13, 2015, 10:59:33 AM4/13/15
to
> Ergo a deficieny!

You are right, but I cannot be too sad with Fortran :-)

Some features are missing, but I cannot define Fortran "inadequate", I am sorry :-)

Anyhow, what do you think about the necessity to catch each pointers usage inside a select type: is it necessary for some reasons, or is it only an addition of verbosity?

My best regards,

Damian Rouson

unread,
Apr 13, 2015, 1:41:25 PM4/13/15
to
On Friday, April 10, 2015 at 2:45:18 PM UTC-7, Noob wrote:
> Hi there,
>
> I'm wondering whether or not using class(*) imply in any extra
> performance penalty compared with class(foo) (which I'm calling
> "regular" polymorphism). To be honest, I'm only guessing that
> passing around polymorphic variables and the select type construct
> imply in performance penalty.

Be wary of any generalizations about performance penalties related to language features that are as versatile as polymorphism. On one hand, there are obvious penalties such those associated with not being able to determine at compile time which type-bound procedure at which level in a class hierarchy will be invoked by a given reference to the procedure. Such uncertainty limits interprocedural optimizations, for example. The compiler can't optimize across procedures if it can't know what the procedures are.

On the other hand, the above penalties can be made negligible by smart design. Consider that the more recent versions of the PSBLAS parallel numerical linear algebra library (http://www.ce.uniroma2.it/psblas/) use polymorphism throughout and achieve performance results nearly identical to the previous versions without polymorphism. Also, the most recent version of PSBLAS use object-oriented design (OOD) patterns to facilitate flexible use of hybrid CPU/GPU platforms. In this regard, OOD (including lots of polymorphism) enhances performance.

As always, profile your code and go into any discussions of performance armed with data about your particular application. Discuss the results with your compiler vendor. Find your bottlenecks and focus your energies there rather than on language features that can be used in many very different ways. As I frequently say when questions such as this one come up, performance-related problems attributed to object-oriented programming (OOP) are often OOD problems in disguise.

I'm including two references below. I don't have a copy of the first one immediately available to me, but based on the final sentence of the abstract, I think it will demonstrate that PSBLAS incurs no performance penalty associated with smart use of polymorphism throughout the package. The second paper describes the role of polymorphism in exploiting hybrid platforms. The latter paper is available via open-access at http://www.hindawi.com/journals/sp/2014/469753/abs/.

Damian

S. Filippone and A. Buttari. Object-Oriented Techniques for Sparse Matrix Computations in Fortran 2003. ACM Trans. on Mathematical Software, 2012, Volume 38, No. 4.

V. Cardellini, S. Filippone, D. Rouson: Design patterns for sparse-matrix computations on hybrid CPU/GPU platforms. Scientific Programming, vol 22, pp. 1-19, 2014.

Stefano Zaghi

unread,
Apr 13, 2015, 3:06:34 PM4/13/15
to
<<<
As always, profile your code and go into any discussions of performance armed with data about your particular application. Discuss the results with your compiler vendor. Find your bottlenecks and focus your energies there rather than on language features that can be used in many very different ways. As I frequently say when questions such as this one come up, performance-related problems attributed to object-oriented programming (OOP) are often OOD problems in disguise.
>>>
I totally agree, I would like to sculpt this sentence on a marble slab.

Can you explain your view (if any) on how use unlimited polymorphic class as a generic container? I admit I have not yet read your book...

My best regards

Damian Rouson

unread,
Apr 14, 2015, 3:30:06 AM4/14/15
to
On Monday, April 13, 2015 at 12:06:34 PM UTC-7, Stefano Zaghi wrote:
> <<<

>
> Can you explain your view (if any) on how use unlimited polymorphic class as a generic container? I admit I have not yet read your book...
>
> My best regards

I have found very limited use for unlimited polymorphism in my own code. I have had some discussions with the PSBLAS project lead around using unlimited polymorphism to construct a linked list that would be useful in storing items in a stack to support error handling. Despite mutual interest, the idea hasn't risen to the top of our or agendas so I don't have an informed opinion, but my gut goes with Ian's first response that (1) CLASS(*) is not an appropriate mechanism for supporting generic programming and (2) if you find yourself using SELECT TYPE frequently, then it's a good time to identify and reconsider the design decision that is driving the need for type guarding. I have been surprised how often I can eliminate SELECT TYPE if I work at it (and have the right people reviewing my code and holding forcing me to justify my choices).

Looking at the Metcalf, Reid, and Cohen example (Appendix E) cited earlier in this thread, it's interesting to note that the only operations on the list that do not involve type guarding are basic list management tasks (list construction and item appending and deleting for example) As soon as one wants to do something as simple as printing a list item, type guarding crops up.

I do have some hope hope for generic programming to appear in Fortran 202X because there are people on the committee who would like to see it, but I'm certain it won't resemble C++ templates and it needs to interact harmoniously with the one limited generic facility currently in the language: parameterized derived types. Apparently there have been some formal proposals made to the committee in favor of parameterized modules in the past and these might be the way to go if the idea can be revived and updated to mesh cleanly with the current language features.

The only case in which I've used CLASS(*) in production code is in conjunction with what my book refers to as the Object pattern: a universal parent class that every class in my project extends (much like the Object class in Java -- hence the name). I write routines similar to C assertions that I invoke as follows:

call assert( x>0, "non-positive x", x)

A simple assertion utility then looks like

subroutine assert( assertion, message, datum )
use iso_fortran_env, only : error_unit
logical, intent(in) :: assertion
character(len=*), intent(in) :: message
class(*), intent(in) :: datum
if (.not. assertion) then
select type(datum)
type is (real)
write(error_unit,*) "Assertion failed with message ",message," for datum ",datum
error stop
class is(object)
write(error_unit,*) "Assertion failed with message ",message," for datum ",datum
error stop
class default
error stop "unrecognized datum type"
end select
end if
end subroutine

where the "object" is an abstract type with a deferred binding that forces all child types to implement derived type I/O. Thus I find unlimited polymorphism useful when I want to do something very general that I can support at the highest levels in my class hierarchy so that I'm only using SELECT TYPE to distinguish intrinsic data from one derived type that can be used universally to reference any other derived type in my project.

I would be able to get rid of even this latter use of SELECT TYPE if my declaration could somehow indicate that "datum" must simply be a type that supports a certain abstract interface (the one for derived type I/O in the above example). I am also hopeful that a mechanism for such declarations could make it into Fortran 202X. Dan Nagle and I have talked about working defining such a feature after the Fortran 2015 feature set is finalized.

Damian

Stefano Zaghi

unread,
Apr 14, 2015, 4:15:50 AM4/14/15
to
Dear Damian,

thank you very much for your detailed analysis.


<<< but my gut goes with Ian's first response that
(1) CLASS(*) is not an appropriate mechanism for supporting generic programming
>>>

This sentence resembles as "dogmatic". To my knowledge, if we exclude "nice" tricks as macros-include-preprocessing_tools..., Fortran has two main way for achieving generic programming (that, indeed, is not my main concern, I just would like to define a generic list of reals, integers or whatever I want as I define an array):

1) using intrinsic "transfer" function for store a generic type as a "molded" (intrinsic) one, e.g. https://github.com/szaghi/single-linked-list/blob/master/src/Data_Type_SL_List.f90#L54

2) using unlimited polymorphic class, e.g. https://github.com/szaghi/OFF/blob/testing/src/Data_Type_Tree.f90#L210

Using inheritance for extending a base (maybe abstract) type is not generic, is just OOP for me.

Surely there are ways to achieve generic type. If you a standard one with no tricks, please let me know.

<<<
(2) if you find yourself using SELECT TYPE frequently, then it's a good time to identify and reconsider the design decision that is driving the need for type guarding
>>>

I completely agree. This is the reason why I (ab)use of pointer associations. Before I found that this "style" is not standard, I was thinking that associated a typed pointer to an unlimited polymorphic one was the right was to trim unnecessary type guarding: I have very low number of select type in my codes. Now that I now that this kind of pointer association is not standard, I have to re-design data as you suggest.

<<<
I have been surprised how often I can eliminate SELECT TYPE if I work at it (and have the right people reviewing my code and holding forcing me to justify my choices)
>>>

You are right, but I am not so lucky to have so kind people to drive me :-)

<<<
Looking at the Metcalf, Reid, and Cohen example (Appendix E) cited earlier in this thread, it's interesting to note that the only operations on the list that do not involve type guarding are basic list management tasks (list construction and item appending and deleting for example) As soon as one wants to do something as simple as printing a list item, type guarding crops up.
>>>

Again absolutely right, thus I have to reinvent the wheel and (ab)use of pointer associations.


<<<
I do have some hope hope for generic programming to appear in Fortran 202X because there are people on the committee who would like to see it, but I'm certain it won't resemble C++ templates and it needs to interact harmoniously with the one limited generic facility currently in the language: parameterized derived types. Apparently there have been some formal proposals made to the committee in favor of parameterized modules in the past and these might be the way to go if the idea can be revived and updated to mesh cleanly with the current language features.
>>>

Good news and bad news... Happy to hear that people on the committee are "sensible" on generic programming, but define parametrized derived types as generic is overvaluing them.

<<<
...
where the "object" is an abstract type with a deferred binding that forces all child types to implement derived type I/O. Thus I find unlimited polymorphism useful when I want to do something very general that I can support at the highest levels in my class hierarchy so that I'm only using SELECT TYPE to distinguish intrinsic data from one derived type that can be used universally to reference any other derived type in my project.
>>>

I think that extending an abstract type is not so general: when I define an array of reals I am not extending the definition of array (or yes?). I found useful (and I use this really in production) to define and abstract type when I have few types (up to the order of 10) that are slightly different but that must have some base features, e.g. in my case I have an abstract Type_File_Base and a set of Type_File_Options, Type_File_Fluids, Type_File_Mesh... extending the base, but if the types become more than 10 this way is very "boring".

Anyhow, thank you very much for your suggestions, they are very appreciated.

Stefano

Wolfgang Kilian

unread,
Apr 14, 2015, 4:17:56 AM4/14/15
to
On 14.04.2015 09:30, Damian Rouson wrote:
> On Monday, April 13, 2015 at 12:06:34 PM UTC-7, Stefano Zaghi wrote:
>> <<<
>
>>
>> Can you explain your view (if any) on how use unlimited polymorphic class as a generic container? I admit I have not yet read your book...
>>
>> My best regards
>
> I have found very limited use for unlimited polymorphism in my own code. I have had some discussions with the PSBLAS project lead around using unlimited polymorphism to construct a linked list that would be useful in storing items in a stack to support error handling. Despite mutual interest, the idea hasn't risen to the top of our or agendas so I don't have an informed opinion, but my gut goes with Ian's first response that (1) CLASS(*) is not an appropriate mechanism for supporting generic programming and (2) if you find yourself using SELECT TYPE frequently, then it's a good time to identify and reconsider the design decision that is driving the need for type guarding. I have been surprised how often I can eliminate SELECT TYPE if I work at it (and have the right people reviewing my code and holding forcing me to justify my choices).
>
> Looking at the Metcalf, Reid, and Cohen example (Appendix E) cited earlier in this thread, it's interesting to note that the only operations on the list that do not involve type guarding are basic list management tasks (list construction and item appending and deleting for example) As soon as one wants to do something as simple as printing a list item, type guarding crops up.
>
> I do have some hope hope for generic programming to appear in Fortran 202X because there are people on the committee who would like to see it, but I'm certain it won't resemble C++ templates and it needs to interact harmoniously with the one limited generic facility currently in the language: parameterized derived types. Apparently there have been some formal proposals made to the committee in favor of parameterized modules in the past and these might be the way to go if the idea can be revived and updated to mesh cleanly with the current language features.

That's good news. So far I had the impression that apart from minor
revisions, the current work is exclusively on C interop and coarrays.
If actual ideas about generic programming are already being discussed,
it would be interesting if a committee member could comment in this
newsgroup ...?

(Extending PDT towards generic (abstract) types as parameters might be a
possibility. This should work well with OO patterns in Fortran. I'd
also rather not support a carbon copy of C++ idioms. I saw an older
proposal about parameterized modules, which appeared somewhat too
coarse-grained to be universally useful.)

-- Wolfgang

> The only case in which I've used CLASS(*) in production code is in conjunction with what my book refers to as the Object pattern: a universal parent class that every class in my project extends (much like the Object class in Java -- hence the name). I write routines similar to C assertions that I invoke as follows:
>
> call assert( x>0, "non-positive x", x)
>
> A simple assertion utility then looks like
>
> subroutine assert( assertion, message, datum )
> use iso_fortran_env, only : error_unit
> logical, intent(in) :: assertion
> character(len=*), intent(in) :: message
> class(*), intent(in) :: datum
> if (.not. assertion) then
> select type(datum)
> type is (real)
> write(error_unit,*) "Assertion failed with message ",message," for datum ",datum
> error stop
> class is(object)
> write(error_unit,*) "Assertion failed with message ",message," for datum ",datum
> error stop
> class default
> error stop "unrecognized datum type"
> end select
> end if
> end subroutine
>
> where the "object" is an abstract type with a deferred binding that forces all child types to implement derived type I/O. Thus I find unlimited polymorphism useful when I want to do something very general that I can support at the highest levels in my class hierarchy so that I'm only using SELECT TYPE to distinguish intrinsic data from one derived type that can be used universally to reference any other derived type in my project.
>
> I would be able to get rid of even this latter use of SELECT TYPE if my declaration could somehow indicate that "datum" must simply be a type that supports a certain abstract interface (the one for derived type I/O in the above example). I am also hopeful that a mechanism for such declarations could make it into Fortran 202X. Dan Nagle and I have talked about working defining such a feature after the Fortran 2015 feature set is finalized.

> Damian
>


giac...@gmail.com

unread,
Apr 14, 2015, 5:28:58 AM4/14/15
to
I follow with a lot of interest this discussion, because I'm an "old school" Fortran programmer that only recently is approaching to OOP.

I think that strong typing is one of the best Fortran features, but for modern and very useful numerical codes, an high level of flexibility is mandatory: this can be in conflict with the current standard, as, for example, the "(ab)use of pointer association" made by Stefano Zaghi.

I've read that there are a lot of tricks and different ways (that can also be more efficient) to achieve a similar result, but my noob question is: why? Why I've to use a not straightforward way or reinvent the wheel to obtain a generic data type? From my point of view this sound like a tedious manner to follow the standard without evaluating if the standard is "modern" enough.

Giacomo

Damian Rouson

unread,
Apr 14, 2015, 6:20:31 AM4/14/15
to
On Tuesday, April 14, 2015 at 1:17:56 AM UTC-7, Wolfgang Kilian wrote:
>
> That's good news. So far I had the impression that apart from minor
> revisions, the current work is exclusively on C interop and coarrays.

What you're saying is true of Fortran 2015. I was expressing optimism for something related to generic programming in the subsequent standard (202X).

> If actual ideas about generic programming are already being discussed,
> it would be interesting if a committee member could comment in this
> newsgroup ...?

I'm not aware of any discussion of generic programming on the Fortran committee mailing lists or in the meetings recently. I'm just saying that I know there are at least a few committee members (3 or 4) who would like to see it happen and are likely to make a run at developing a proposal to present to the whole committee at the appropriate time. And I know one or two people who are considering joining the committee and who would be very motivated to work on such proposal. All of my conversations on the subject so far have been informal and one-on-one so my optimism could very well be naive. We'll see what happens after Fortran 2015 has been finalized and work on the next standard begins.

Damian

Noob

unread,
Apr 14, 2015, 6:36:59 AM4/14/15
to
Is /Scientific Software Design: The Object-Oriented Way/ going to be
released as e-book anytime in the future? I'd love to have it in
my Kindle e-reader.

Thank you for the references in your first post and for the comments.

Wolfgang Kilian

unread,
Apr 14, 2015, 7:22:43 AM4/14/15
to
It's reassuring that Fortran will be on track. From some previous
comments in this newsgroups, I got the impression that the committee was
lacking volunteers for possible major upgrades.

> Damian
>

-- Wolfgang

Noob

unread,
Apr 14, 2015, 7:27:38 AM4/14/15
to
I think the flexibility comes through things like type extension,
inheritance and overriding of TBPs. Those features can be used in very
efficient ways, as people have been showing here.

I was too thinking that unlimited polymorphism was the ultimate tool
for generic programing in Fortran but I now see that's not how it should
be done. Well, it is not how it is done in other languages that I know
of. From what I can see now, among the alternatives, the include trick
seems to be the one that resembles the most the way it is done by means
of templates. I mean, different object codes will be created, one for
each desired type. From this point of view, I'd now say that the INCLUDE
trick is the appropriate Fortran way of doing it for now and that using
CLASS(*) for this is to abuse a concept. In a way, I think this whole
thread is just reaffirming the validity of Ian Harvey's first reply to
me.

Juan Domínguez

unread,
Apr 14, 2015, 8:33:39 AM4/14/15
to
On Friday, April 10, 2015 at 5:45:18 PM UTC-4, Noob wrote:
> Hi there,
>
> I'm wondering whether or not using class(*) imply in any extra
> performance penalty compared with class(foo) (which I'm calling
> "regular" polymorphism). To be honest, I'm only guessing that
> passing around polymorphic variables and the select type construct
> imply in performance penalty.
>
> I was about to finish implementing my (I'd call genuinely) generic
> doubly-linked list (with sorting) and I realized it was actually
> easy to make it a list of not only variables whose type is an
> extension of a previously predetermined abstract derived type but
> actually a list of also scalar variables of all intrinsic types,
> if I use class(*) in the appropriate places.
>
> (Well, actually, this opens the possibility of including data
> which may not be proper finalized and lead to memory leak, right?
> I'm working on that).
>
> 'Not sure it is a good idea but right now it can also hold data of
> different types in different nodes and I've also created a rule to
> sort the list when it is "heterogeneous".
>
> So, any reason (from the point of view of performance or otherwise)
> not to use class(*) when I'm already using polymorphism all around?
>
> Thank you.

I don't know if you remember but generics where included in Java 1.5, all the containers in Java before 1.5 where containers of java.lang.Object and to do anything with the object you had to cast it to the class you wanted. The problem was that there were many ClassCastExceptions, many runtime errors and many lines of "if(my_object instanceof SomeClass)" ... The same is happening with fortran's class(*), I'm always tempted to write generic containers but thinking about changing all the code when "true generics" arrive to the standard always kept me from doing it. I think fortran will improve a lot if generic programming is included in the language, I mean, I can live without exceptions and others, but not without generic programming, it is keeping me from doing many things in fortran.

Gary Scott

unread,
Apr 14, 2015, 9:06:04 AM4/14/15
to
I FORBID the committee to add any more new features before they've
incorporated a proper bit string type...I've been waiting for 40+ years
for this simple thing...

Stefano Zaghi

unread,
Apr 14, 2015, 9:47:03 AM4/14/15
to

> I think the flexibility comes through things like type extension,
> inheritance and overriding of TBPs. Those features can be used in very
> efficient ways, as people have been showing here.

I think this does not concern with a really generic container as your original question on generic doubly-linked list. Type extension, inheritance, overriding TBPs are OOP features, very useful features, but they are not enough for a really generic container.

In my view it seems like the standard has provided a cool feature, the unlimited polymorphic class(*) exploiting which we can write a real generic container, but the standard itself says "no! you cannot abuse of my class(*)..."

> From what I can see now, among the alternatives, the include trick
> seems to be the one that resembles the most the way it is done by means
> of templates. I mean, different object codes will be created, one for
> each desired type.

It seems the description of many slightly different types, not the one of a generic type. Maybe your aim is different from mine, but with a generic list I mean a generic container as could be an array: you can define an array of real, integer or whatever is your derive type, thus I would like to one generic list where I can store real, integer or whatever I want. I do not like to define many generic list, and with the INCLUDE trick I have to do it. If I have to select a trick I still prefer to use the TRANSFER intrinsic function.

> From this point of view, I'd now say that the INCLUDE
> trick is the appropriate Fortran way of doing it for now and that using
> CLASS(*) for this is to abuse a concept.

We are going into a "philosophic" field, but this use of include can be view also as an abuse, or at least as a border-line usage. I suppose that when include was supported, generic programming was not into the radar.

Now that I realized that associate a typed pointer to an unlimited polymorphic one is not standard, I am thinking that the unlimited polymorphic class(*) is missed chance to bring Fortran into 20xx century.

>I FORBID the committee to add any more new features before they've
>incorporated a proper bit string type...I've been waiting for 40+ years
>for this simple thing...

Great!

My best regards,
Stefano

Noob

unread,
Apr 14, 2015, 11:51:56 AM4/14/15
to
On 14/04/2015 10:47, Stefano Zaghi wrote:
>
>> I think the flexibility comes through things like type extension,
>> inheritance and overriding of TBPs. Those features can be used in very
>> efficient ways, as people have been showing here.
>
> I think this does not concern with a really generic container as your original question on generic doubly-linked list. Type extension, inheritance, overriding TBPs are OOP features, very useful features, but they are not enough for a really generic container.
>

You are right. I was referring to the statement [... high level of
flexibility is mandatory.] and the intention was to remind that we
have some high level of flexibility in Fortran through those elements.

> In my view it seems like the standard has provided a cool feature, the unlimited polymorphic class(*) exploiting which we can write a real generic container, but the standard itself says "no! you cannot abuse of my class(*)..."
>

I'm not sure the standard forbids you. You are required to make sure the
types match, though, by using SELECT TYPE. It is not as simple as a
single statement (a single pointer association), but still possible.
We can use (and abuse of) class(*) but there's always the question of
whether we are creating safe and/or efficient code. This is what
motivated my OP.

>> From what I can see now, among the alternatives, the include trick
>> seems to be the one that resembles the most the way it is done by means
>> of templates. I mean, different object codes will be created, one for
>> each desired type.
>
> It seems the description of many slightly different types, not the one of a generic type. Maybe your aim is different from mine, but with a generic list I mean a generic container as could be an array: you can define an array of real, integer or whatever is your derive type, thus I would like to one generic list where I can store real, integer or whatever I want. I do not like to define many generic list, and with the INCLUDE trick I have to do it. If I have to select a trick I still prefer to use the TRANSFER intrinsic function.
>

No, we agree on the goal. The idea was the same: to declare a generic
list-like container capable of storing all sorts of things. (I
mentioned in my OP that the data could also be heterogeneous, but I
really do not require that.) However, I want it to be not only
syntactically easy to do but also that it result in solid code.

>> From this point of view, I'd now say that the INCLUDE
>> trick is the appropriate Fortran way of doing it for now and that using
>> CLASS(*) for this is to abuse a concept.
>
> We are going into a "philosophic" field, but this use of include can be view also as an abuse, or at least as a border-line usage. I suppose that when include was supported, generic programming was not into the radar.
>
> Now that I realized that associate a typed pointer to an unlimited polymorphic one is not standard, I am thinking that the unlimited polymorphic class(*) is missed chance to bring Fortran into 20xx century.
>

I have never programmed in Java, but Juan Domínguez's reply to me seems
to suggest that Java moved /away/ from a strategy like this. (Where
one would have to be constantly checking the dynamic type of
something or havoc would happen.) It looks then like "generic" in other
languages (other than the only other one I know something about) tend
to mean /specific/ object code being created for the user. I can only
assume there's a good reason for that.

I hope Fortran comes to support a broader type of generic programming
in the future (beside derived type parametrization). Until then, we do
what we can :)

>> I FORBID the committee to add any more new features before they've
>> incorporated a proper bit string type...I've been waiting for 40+ years
>> for this simple thing...
>

[Gary Scott's words]

> Great!
>
> My best regards,
> Stefano
>

Cheers!

Stefano Zaghi

unread,
Apr 14, 2015, 12:24:49 PM4/14/15
to
Dear Noob, thank you for your replay.

> You are right. I was referring to the statement [... high level of
> flexibility is mandatory.] and the intention was to remind that we
> have some high level of flexibility in Fortran through those elements.
>

I agree, present Fortran is more flexible and it OOP "enabled".


> I'm not sure the standard forbids you. You are required to make sure the
> types match, though, by using SELECT TYPE. It is not as simple as a
> single statement (a single pointer association), but still possible.
> We can use (and abuse of) class(*) but there's always the question of
> whether we are creating safe and/or efficient code. This is what
> motivated my OP.

I am conscious of possible penalties in efficiency, but as Damian says this must checked by experiments. Anyhow, as I stated above, if I want to maximize speed I use array, if I use a list is to simplify my life when speed is not crucial. You are right: I can trap all pointers into a selected type, but this clutters the code and (again) as Damian says this is an evidence that the code must be "refactored". I dream a time when Standard "legalize" the abuse of unlimited polymorphic pointers :-)

> No, we agree on the goal. The idea was the same: to declare a generic
> list-like container capable of storing all sorts of things. (I
> mentioned in my OP that the data could also be heterogeneous, but I
> really do not require that.) However, I want it to be not only
> syntactically easy to do but also that it result in solid code.

I agree. Until I discovered that my abuse of pointers association is not standard (exploiting a great bug of Intel Fortran :-), I have tested that the code is "solid/sane": this kind of pointers is used into a small-sized loop where the inner computations (the ones done in parallel) are of orders of magnitudes greater than the outer (parallelized safely via MPI), thus there is no speed penalty in using the abused pointers association.

> I have never programmed in Java, but Juan Domínguez's reply to me seems
> to suggest that Java moved /away/ from a strategy like this. (Where
> one would have to be constantly checking the dynamic type of
> something or havoc would happen.) It looks then like "generic" in other
> languages (other than the only other one I know something about) tend
> to mean /specific/ object code being created for the user. I can only
> assume there's a good reason for that.

I have no experience with Java, but I am comfortable with Python. In Python a list can containing everything, it is really generic. Besides, there are other nice containers... I am not sure, but I think that Python codes (if well written) are faster than an equivalent well-written java counterparts. At my knowledge, there is no plans to trim out generic containers from Python, there should be good reason for that. Fortran is the fastest language in the west, but if it allow to relax some constrain it can become also the simplest: this can be achieved without compromising all the good that come from strongly typed specification.

> I hope Fortran comes to support a broader type of generic programming
> in the future (beside derived type parametrization). Until then, we do
> what we can :)

You are right, maybe one thing that we can do is to make sensible the committee board to the nice features of generic programming :-)

My best regards.

FortranFan

unread,
Apr 14, 2015, 2:52:26 PM4/14/15
to
On Tuesday, April 14, 2015 at 8:33:39 AM UTC-4, Juan Domínguez wrote:

>
> ... The same is happening with fortran's class(*), I'm always tempted to write generic containers but thinking about changing all the code when "true generics" arrive to the standard always kept me from doing it. I think fortran will improve a lot if generic programming is included in the language, I mean, I can live without exceptions and others, but not without generic programming, it is keeping me from doing many things in fortran.


I agree.

I wonder how long will it be before the concept of generic programming and the present aspect of parameterized derived types can get merged in Fortran to allow something along the following lines for a generic container, something that is common in Java and similar object-oriented languages:

--- begin pseudo code ----
module m

implicit none

private

type, public :: box(T)

private

generic, type :: T !.. defines T to be of generic 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 !.. an integer box

call foo%set( 42 )

print *, foo%get()

end program p

--- end pseudo code ----

I feel all the pieces are there and the entire concept has been laid out in many languages. Separately, note Fortran 2008 allows the TYPE statement to be used for all intrinsic types too, so the syntax like the one in the above pseudo code shouldn't come across as too alien.

I wish a few minds can get together and put together a specification!!

By the w

Wolfgang Kilian

unread,
Apr 14, 2015, 4:02:54 PM4/14/15
to
Well, Python is not exactly a strongly typed language.

In languages that don't enforce a strong type system, there is no need
for separating polymorphism and genericity. Python constructs
deliberately make use of both concepts. If done well, this is quite
versatile.

Fortran is supposed to stay a strongly typed language with some
exceptions, e.g. type promotion for numbers. One might argue about
this, but there are reasons. Polymorphic and generic constructs then
correspond to code selection at runtime or at compile time,
respectively. (Not counting optimization by a smart compiler.)
Polymorphism is well supported, but genericity is only partially
supported: generic identifiers, but no generic types beyond current PDT.

If anybody's interested, look at OCaml, which is a strongly typed
compiled (functional) language. It implements polymorphism by
alternative types and pattern matching, while generic code is realized
by type parameters in functions and types. There are also parameterized
modules, called functors. OCaml has excellent support for container
types and abstract algorithms. At least superficially, it looks like
these particular incarnations of genericity would fit rather well also
in the Fortran context.

>> I hope Fortran comes to support a broader type of generic programming
>> in the future (beside derived type parametrization). Until then, we do
>> what we can :)

I fully agree, while ...

> You are right, maybe one thing that we can do is to make sensible the committee board to the nice features of generic programming :-)

... I'd like the principle of strong typing be kept in future
generic-code syntax. Hopefully, with minimal added complexity.

> My best regards.
>

-- Wolfgang

FortranFan

unread,
Apr 14, 2015, 4:47:06 PM4/14/15
to
So to elaborate further, I hope one can then also do:

--- begin pseudo code ---

program p

use m, only : box

implicit none

type(box(integer)) :: foo !.. a box holding an integer
type(box(real)) :: bar !.. a box holding a floating point value

call foo%set( 42 )
print *, foo%get() !.. should print 42

call bar%set( 3.14 )
print *, bar%get() !.. should print 3.14

end program p
--- end pseudo code ---


And of course, allocatable attributes should be supported as well, possibly along the lines of:

--- begin pseudo code ---
module m

implicit none

private

type, public :: box(T)

private

generic, type :: T !.. defines T to be of generic type

type(T), allocatable :: m_t !.. allocatable component of generic type

contains

...

end module m
--- end pseudo code ---

And also, polymorphic types which may be along the following files:

--- begin pseudo code ---
module m

implicit none

private

type, public :: box(T)

private

generic, class:: T !.. defines T to be of generic polymorphic type

class(T), allocatable :: m_t !.. allocatable component of generic type

contains

...

end module m
--- end pseudo code ---

And while we're at it, the above can be made to work with unlimited polymorphic types too as in

type(box(*)) :: foobar


Just sharing my thoughts on a lazy afternoon having had too much coffee :-)) The sharper minds will hopefully ponder over this and come up with lot better specifications eventually!


Damian Rouson

unread,
Apr 14, 2015, 6:24:33 PM4/14/15
to
On Tuesday, April 14, 2015 at 3:36:59 AM UTC-7, Noob wrote:
>
> Is /Scientific Software Design: The Object-Oriented Way/ going to be
> released as e-book anytime in the future? I'd love to have it in
> my Kindle e-reader.

The eBook is available at

http://www.cambridge.org/us/academic/subjects/engineering/engineering-general-interest/scientific-software-design-object-oriented-way?format=AR

Damian

K

unread,
Apr 14, 2015, 6:37:01 PM4/14/15
to
Hello,
Actually, that looks a lot like something I would want to use. I am sure it can be adapted into a kind of generalisation of the way TBPs work now.
That said, GENERIC seems wrong here, given that it already has a completely different meaning.
Maybe it could be something like:

--pseudo-code here--
type, public :: box(T)
private
class(*), kind :: T !.. defines T to be a class parameter for the box type
class(T), allocatable :: m_t
end type
--
It still feels wrong though, it looks too much like a variable definition.

It could also be useful to restrict the possibilities for the parameter to one class in particular.
--pseudo-code here--
type, public :: box(T)
private
class(whatever), kind :: T !.. defines T to be a class parameter for the box type; T must be of class(whatever)
class(T), allocatable :: m_t ! m_t is guaranteed to be at least of class(whatever), in any circumstances
end type
--
I do not have an use case example right now, though. I thought about something earlier, but forgot while coming back home.

Cheers.

FortranFan

unread,
Apr 14, 2015, 10:55:37 PM4/14/15
to
On Tuesday, April 14, 2015 at 6:37:01 PM UTC-4, K wrote:

>
> Actually, that looks a lot like something I would want to use.

Ok, great.

> .. That said, GENERIC seems wrong here, given that it already has a completely different meaning.

Well, if the committee ever gets around to working on this, they will come up with whatever suits their fancy. The past record is neither particularly elegant nor consistent. I think

a) my suggestion is at least consistent with the pattern of "INTEGER, LEN :: " and "INTEGER, KIND :: " for PDTs. While at it, let us not forget the couple of other meanings for LEN and KIND.

b) the use of GENERIC keyword as a generic binding for type-bound procedures and for a generic type parameter for generic programming purposes as in "GENERIC, TYPE/CLASS :: " should be no hurdle for users to learn and adapt to. If anything, it fits together as well or better than most other keywords in the language.

Stefano Zaghi

unread,
Apr 15, 2015, 12:07:45 AM4/15/15
to
>Well, Python is not exactly a strongly typed language.

I know, I cited Python just as an example against the Java one that Noob and others pursued.

> In languages that don't enforce a strong type system, there is no need
> for separating polymorphism and genericity. Python constructs
> deliberately make use of both concepts. If done well, this is quite
> versatile.

I agree with you.

> Fortran is supposed to stay a strongly typed language with some
> exceptions, e.g. type promotion for numbers. One might argue about
> this, but there are reasons. Polymorphic and generic constructs then
> correspond to code selection at runtime or at compile time,
> respectively. (Not counting optimization by a smart compiler.)
> Polymorphism is well supported, but genericity is only partially
> supported: generic identifiers, but no generic types beyond current PDT.

Unfortunately you are right genericity has very poor support presently, but I am happy Fortran stay strongly typed this is a plus: I am just thinking that in some circumstances more flexibility is good not the evil.

> If anybody's interested, look at OCaml, which is a strongly typed
> compiled (functional) language. It implements polymorphism by
> alternative types and pattern matching, while generic code is realized
> by type parameters in functions and types. There are also parameterized
> modules, called functors. OCaml has excellent support for container
> types and abstract algorithms. At least superficially, it looks like
> these particular incarnations of genericity would fit rather well also
> in the Fortran context.

Thank you very much for the suggestion it looks interesting.

> I'd like the principle of strong typing be kept in future
> generic-code syntax. Hopefully, with minimal added complexity.

I agree, I will never leave strong typing, I am just hoping that besides stronly typed variables I will have the possibility to define a more flexible ones even with risk that these new types are less efficient.

In this framework the subsequent suggestion of FortranFan looks great! We have to wait for 20/30 years...

My best regards

Wolfgang Kilian

unread,
Apr 15, 2015, 3:12:00 AM4/15/15
to
Just two remarks:

(1) There should be a way to specify requirements on type T, probably by
referring to an accessible (abstract) type in the sense of a pattern.
This is analogous to (abstract) interfaces for deferred procedures.

(2) Procedures that use a generic type become type-parameterized
procedures. This dependency should be explict in syntax.

==========
type, abstract :: type_pattern
! require a particular component
integer :: i
contains
! require a particular method
procedure (some_interface), deferred :: eval
...
end type type_pattern

...

type :: box_with_some_functionality (T)
type, generic, implements (type_pattern) :: T
type (T) :: x
contains
procedure, pass :: proc => proc_def (T)
end type

...
type (box (integer)) :: ibox
...
call ibox%proc ()
...


subroutine proc_def (this) parameterized_by (T)
type, generic, implements (type_pattern) :: T
class (box_with_some_functionality (T)), ... :: this
...
call this%x%eval (...) ! enabled by type_pattern
...
j = this%x%i ! enabled by type_pattern
...
call do_something (this%x) ! do_something defined below
...
end subroutine

...

subroutine do_something (x) parameterized_by (T)
type, generic, implements (type_pattern) :: T
type(T), ... x
...
end subroutine

========

and so on. For instance, the pattern could require a comparison method,
and proc_def could implement a sorting algorithm.

And yes, I believe that generic-programming syntax along these lines
makes a lot of sense - but I'm sure there are pitfalls, if this is to
work together with the rest of Fortran. For instance, how to require
standard (generic) arithmetic operators for a pattern which is supposed
to match elementary reals? How does TKR disambiguation apply to
parameterized procedures?

Ian Harvey

unread,
Apr 15, 2015, 3:34:57 AM4/15/15
to
On Monday, 13 April 2015 14:45:17 UTC+10, Stefano Zaghi wrote:
> For the Fortran GURU, what is wrong with the following pseudo code?
>
> type foo::
> class(*), pointer:: d ! A data
> endtype foo
> type(foo):: container
> integer:: i
> allocate(container%d,source=3)
> i => container%d
> print "(I5)", i
>
> In case the data stored is not an integer I will get a runtime error, that I think is enough.

For clarity, note that "will *get* a runtime error" doesn't accurately describe the outcome if the dynamic type doesn't match - if you defined this as extension in the way that it likely behaves with the Intel compiler today. No error will necessarily be reported at runtime, the person executing the program may well remain oblivious to the problem. It is this sort of error that rigorous application of static typing in a language helps prevent.

Contrast that situation with some other languages, where a detectable error can be reported in the case of an invalid "cast".

If you want type safety, then you need some way of telling the Fortran processor what to do when the dynamic type doesn't match. That means in the standard language is the SELECT TYPE construct.

Stefano Zaghi

unread,
Apr 15, 2015, 4:23:27 AM4/15/15
to
> For clarity, note that "will *get* a runtime error" doesn't accurately describe the outcome if the dynamic type doesn't match - if you defined this as extension in the way that it likely behaves with the Intel compiler today. No error will necessarily be reported at runtime, the person executing the program may well remain oblivious to the problem. It is this sort of error that rigorous application of static typing in a language helps prevent.

I perfectly know about that. I just trying to figure out how could be a "future nice behavior". If Fortran committee will be so great to define a standard that will able to produce a "clear runtime error" for types mismatch, this is enough for me. I perfectly know the great benefits of static strongly typed language, indeed this one of the reason I love Fortran, but is it so difficult to think a way to "occasionally" relax this constrain?


> If you want type safety, then you need some way of telling the Fortran processor what to do when the dynamic type doesn't match. That means in the standard language is the SELECT TYPE construct.

I want type safety for the most part of typical programming scenario, but it would be very appreciated if more flexibility can be add in a "friendly way".

I know that the standard way to trap dynamic type mismatch is SELECT TYPE. If I accept the risk of give up compile time checks in flavor of more flexibility and "easy to write" (i.e. avoid cluttering the code with a lot of select type constructs), which is the best standard way? Presently, as you rightly highlight is (ab)usage of SELECT TYPE constructs, but for future improvements what you suggest?

Do you like the idea of FortranFan et al.?

Anyhow, thank you very much for sharing your idea, your experience is very appreciated.

My best regards.

FortranFan

unread,
Apr 15, 2015, 11:03:35 AM4/15/15
to
On Wednesday, April 15, 2015 at 3:12:00 AM UTC-4, Wolfgang Kilian wrote:


> Just two remarks:
>
> (1) There should be a way to specify requirements on type T, probably by
> referring to an accessible (abstract) type in the sense of a pattern.
> This is analogous to (abstract) interfaces for deferred procedures.
>

I assume this falls in the category of "constraints" that some object-oriented languages support with their implementation of generic programming. As long as it is flexible (think optional) and consistent with PDTs, I'm ok.

> (2) Procedures that use a generic type become type-parameterized
> procedures. This dependency should be explict in syntax.
>

If you notice my pseudocode, the syntax does indeed follow the manner of type-parameterized procedures and I'd think that is sufficient unless additional changes are brought in for PDTs:

--- begin pseudo code ---
subroutine set_T(this, val)

class(box(T)), intent(inout) :: this !.. or it can be type(box(T)) too
type(T), intent(in) :: val

this%m_t = val

end subroutine
--- end pseudo code ---


> And yes, I believe that generic-programming syntax along these lines
> makes a lot of sense - but I'm sure there are pitfalls, if this is to
> work together with the rest of Fortran. For instance, how to require
> standard (generic) arithmetic operators for a pattern which is supposed
> to match elementary reals? How does TKR disambiguation apply to
> parameterized procedures?
>

The key is not to get carried away too much. As I mentioned earlier, there are many successful implementations of such generic programming constructs in other languages that Fortran can learn from and bring into its standard. Thing is it does NOT have to be like C++ templates; Java etc. may be better models for generics, I feel.

Wolfgang Kilian

unread,
Apr 15, 2015, 1:12:20 PM4/15/15
to
On 04/15/2015 05:03 PM, FortranFan wrote:> On Wednesday, April 15, 2015
at 3:12:00 AM UTC-4, Wolfgang Kilian wrote:
>
>
>> Just two remarks:
>>
>> (1) There should be a way to specify requirements on type T, probably by
>> referring to an accessible (abstract) type in the sense of a pattern.
>> This is analogous to (abstract) interfaces for deferred procedures.
>>
>
> I assume this falls in the category of "constraints" that some
object-oriented languages support with their implementation of generic
programming. As long as it is flexible (think optional) and consistent
with PDTs, I'm ok.

I don't think that constraints on a generic type should be allowed to be
optional (implicit).

Consider (T is a generic type)

...
type(T) :: x

...
call x%foo (u)
...
y = x%i + z
...
y = x%bar (z)

Without the explicit type pattern (signature) of T, the compiler won't
know anything about the types / interfaces of foo, i, bar. It doesn't
even know whether bar is an array or a function.

It can give an interpretation only when it produces and compiles an
instance with a concrete realization of T. If the generic code is in an
external "template" library, the user of the library can't understand
the behavior of the an instance of the generic code, or compiler error
messages, without access to the source of the library. Even worse, if
implicit constraints are accidentally violated, an instance may compile
and run seamlessly but produce garbage results.

In essence, the compiler should check and digest the generic code, like
any other code, at the point where it is read. Thus, all properties of
the components of T that affect the code interpretation must be explicit.

This is roughly analogous to explicit interfaces for external
procedures, which are recommended (but not enforced) in modern Fortran.
Many problems of legacy applications originate from implicit
interfaces of library procedures.

>> (2) Procedures that use a generic type become type-parameterized
>> procedures. This dependency should be explict in syntax.
>>
>
> If you notice my pseudocode, the syntax does indeed follow the manner
of type-parameterized procedures and I'd think that is sufficient unless
additional changes are brought in for PDTs:
>
> --- begin pseudo code ---
> subroutine set_T(this, val)
>
> class(box(T)), intent(inout) :: this !.. or it can be
type(box(T)) too
> type(T), intent(in) :: val
>
> this%m_t = val
>
> end subroutine
> --- end pseudo code ---

Again, I'd require the dependency on T and the relevant constraints on T
(even if empty) to be explicit in the subroutine interface.

>
>> And yes, I believe that generic-programming syntax along these lines
>> makes a lot of sense - but I'm sure there are pitfalls, if this is to
>> work together with the rest of Fortran. For instance, how to require
>> standard (generic) arithmetic operators for a pattern which is supposed
>> to match elementary reals? How does TKR disambiguation apply to
>> parameterized procedures?
>>
>
> The key is not to get carried away too much. As I mentioned earlier,
there are many successful implementations of such generic programming
constructs in other languages that Fortran can learn from and bring into
its standard. Thing is it does NOT have to be like C++ templates; Java
etc. may be better models for generics, I feel.
>

-- Wolfgang


FortranFan

unread,
Apr 15, 2015, 2:27:22 PM4/15/15
to
On Wednesday, April 15, 2015 at 1:12:20 PM UTC-4, Wolfgang Kilian wrote:

> ..
> I don't think that constraints on a generic type should be allowed to be
> optional (implicit).
>
> Consider (T is a generic type)
>
> ...
> type(T) :: x
>
> ...
> call x%foo (u)
> ...
> y = x%i + z
> ...
> y = x%bar (z)
>

In my experience with generics with Java and Microsoft .NET, I feel the full benefits of generics get realized when constraints are optional - that's how these languages have it - otherwise the value diminishes greatly.

There are many instances when one simply needs to create containers to hold any type, so one does not specify any constraints. Example in Java:

class Container<T> {
T m_ob;

Container(T o) {
m_ob = o;
}

T getob() {
return m_ob;
}

}

But there are situations when a class works with data of a specific type and its extensions and then it makes sense to apply a constraint as in:

class GenNumPrinter<T extends Number & Comparable<T>> {

void print (T m_Num) {
System.out.println (m_Num.intValue ());
}

}

Anyways, it is important what gets implemented in Fortran, if it ever does, is based on a study of what works best in other successful approaches (e.g., Java and Microsoft.NET which constitute probably >90% of users employing OOD/OOP methodologies globally) and adapting in a flexible manner. It will thus help if those developing specifications in Fortran for generics have a solid understanding of what works and does not work in such globally popular domains instead of predetermining constraints must be non-optional.

Wolfgang Kilian

unread,
Apr 15, 2015, 4:05:32 PM4/15/15
to
On 04/15/2015 08:27 PM, FortranFan wrote:
> On Wednesday, April 15, 2015 at 1:12:20 PM UTC-4, Wolfgang Kilian wrote:
>
>> ..
>> I don't think that constraints on a generic type should be allowed to be
>> optional (implicit).
>>
>> Consider (T is a generic type)
>>
>> ...
>> type(T) :: x
>>
>> ...
>> call x%foo (u)
>> ...
>> y = x%i + z
>> ...
>> y = x%bar (z)
>>
>
> In my experience with generics with Java and Microsoft .NET, I feel the full benefits of generics get realized when constraints are optional - that's how these languages have it - otherwise the value diminishes greatly.
>
> There are many instances when one simply needs to create containers to hold any type, so one does not specify any constraints. Example in Java:
>
> class Container<T> {
> T m_ob;
>
> Container(T o) {
> m_ob = o;
> }
>
> T getob() {
> return m_ob;
> }
>
> }

Convenient yes, just slightly unsafe. The pattern is simple, just one
method of T called (assignment). Since assignment will exist for any
type, the pattern is redundant, but ... in Fortran the assignment
operation may resolve to defined assignment and in principle cause all
sorts of side-effects, cross-image data transfer etc. You may thus want
to specify a constraint that assignment is PURE, for instance. (You may
say that who writes impure defined assignment will get what he deserves,
but if the compiler can check, it can optimize, etc.)

> But there are situations when a class works with data of a specific type and its extensions and then it makes sense to apply a constraint as in:
>
> class GenNumPrinter<T extends Number & Comparable<T>> {
>
> void print (T m_Num) {
> System.out.println (m_Num.intValue ());
> }
>
> }
>
> Anyways, it is important what gets implemented in Fortran, if it ever does, is based on a study of what works best in other successful approaches (e.g., Java and Microsoft.NET which constitute probably >90% of users employing OOD/OOP methodologies globally) and adapting in a flexible manner. It will thus help if those developing specifications in Fortran for generics have a solid understanding of what works and does not work in such globally popular domains instead of predetermining constraints must be non-optional.
>

-- Wolfgang

K

unread,
Apr 15, 2015, 4:22:51 PM4/15/15
to
Yes, I think that would be useful. It is somewhat a generalisation of what I meant by "class(whatever), kind :: T".
I am glad you wrote that. Actually, I thought of something along those lines, but did not get very far.
I think it might be useful to have a feature similar to Java's interfaces, or Objective-C's protocols (although there are similar things in many languages). I like PROTOCOL better than INTERFACE that has already several meanings, though.

Basically, a protocol is a list of methods (procedures), that is not that useful in itself. The interesting thing is that one can define a class (derived type) that inherits from another type, but also implements the protocol. This means that the type has an implementation for all the procedures defined in the protocol.
This is very useful to express the fact that a type *has* certain characteristics (is sortable, can be put into trees, can be saved to a file, etc), while standard inheritance shows what the type *is*.
I might well be wrong, but I do not see any disadvantage in terms of safety or performance, compared to the current situation.
That said, while this could be useful with support for generic programming, but is only tangentially related, I think. It might be a good addition in itself regardless of generic programming support.


> And yes, I believe that generic-programming syntax along these lines
> makes a lot of sense - but I'm sure there are pitfalls, if this is to
> work together with the rest of Fortran. For instance, how to require
> standard (generic) arithmetic operators for a pattern which is supposed
> to match elementary reals? How does TKR disambiguation apply to
> parameterized procedures?

Well yes, I am sure there are many holes, and getting a consistent syntax would be hard. Although I have been writing code in Fortran for years, I won't pretend that I am an expert. Oh well, at least it is an interesting thought experiment.

Cheers.

K

unread,
Apr 15, 2015, 4:29:39 PM4/15/15
to
Le mercredi 15 avril 2015 03:55:37 UTC+1, FortranFan a écrit :
> On Tuesday, April 14, 2015 at 6:37:01 PM UTC-4, K wrote:
>
> >
> > Actually, that looks a lot like something I would want to use.
>
> Ok, great.
>
> > .. That said, GENERIC seems wrong here, given that it already has a completely different meaning.
>
> Well, if the committee ever gets around to working on this, they will come up with whatever suits their fancy. The past record is neither particularly elegant nor consistent.

I agree with you. Also, what I should have written is: "GENERIC seems wrong here, given that it already has a completely different meaning, in a very similar context (a derived type definition, the main difference would be the relative position of a CONTAINS line)".

>
> a) my suggestion is at least consistent with the pattern of "INTEGER, LEN :: " and "INTEGER, KIND :: " for PDTs. While at it, let us not forget the couple of other meanings for LEN and KIND.
>
> b) the use of GENERIC keyword as a generic binding for type-bound procedures and for a generic type parameter for generic programming purposes as in "GENERIC, TYPE/CLASS :: " should be no hurdle for users to learn and adapt to. If anything, it fits together as well or better than most other keywords in the language.

Yes, there are inconsistencies and plain weirdness in Fortran already. I just thought it might be valuable in terms of consistency and clarity to generalise and extend the concept of PDT. I know many programmers (or vendors) hate PDTs; to me they look like a formidable wasted opportunity.

Cheers.

Stefano Zaghi

unread,
Apr 16, 2015, 3:25:27 AM4/16/15
to
For people involved into Fortran standard definition: one very young, emerging, promising programming language is http://nim-lang.org/. Among its features there are:

+ A fast non-tracing garbage collector that supports soft real-time systems

+ System programming features: Ability to manage your own memory and access the hardware directly. Pointers to garbage collected memory are distinguished from pointers to manually managed memory.

+ Zero-overhead iterators.

+ Cross-module inlining.

+ Dynamic method binding with inlining and without virtual method table.

+ Compile time evaluation of user-defined functions.

+ Whole program dead code elimination: Only used functions are included in the executable.

è Value-based datatypes: For instance, objects and arrays can be allocated on the stack.

+ Built-in high level datatypes: strings, sets, sequences, etc.

+ Modern type system with local type inference, tuples, variants, generics, etc.

+ User-defineable operators; code with new operators is often easier to read than code which overloads built-in operators. For example, a =~ operator is defined in the re module.

+ Macros can modify the abstract syntax tree at compile time.

+ Macros can use the imperative paradigm to construct parse trees. Nim does not require a different coding style for meta programming.

+ Macros cannot change Nim's syntax because there is no need for it. Nim's syntax is flexible enough.

+ Statements are grouped by indentation but can span multiple lines. Indentation must not contain tabulators so the compiler always sees the code the same way as you do.

Maybe Fortran can take inspiration also from this great project: I have not yet tried Nim, but some features are interesting. I think it cannot compete with Fortran for scientific computation, but Fortran can take its "sane" approach for modern programming.

My best regards.

Espen Myklebust

unread,
Apr 16, 2015, 4:19:30 AM4/16/15
to
Wouldn't compiler have this information upon instantiation of the MODULE where this source code appears? The MODULE would not be compiled into object code until it is instantiated with an actual/concrete type... The "pattern" for the code would be stored in the .mod file which works as a precompiled header file (thank you FortranFan:). IMO this is no different from using a non-generic type: the compiler have to check at compile-time that it can resolve all the names ant that the program logic follows the rules of Fortran.

> It can give an interpretation only when it produces and compiles an
> instance with a concrete realization of T. If the generic code is in an
> external "template" library, the user of the library can't understand
> the behavior of the an instance of the generic code, or compiler error
> messages, without access to the source of the library. Even worse, if
> implicit constraints are accidentally violated, an instance may compile
> and run seamlessly but produce garbage results.
>
Any external library have to be documented in some way for the user to know which entities are defined within it etc., this would be no no different, e.g.:
the type T must have components foo and i and a TBP named bar, and the bar procedure must have an interface like this and should (ideally, in order for the code to make sense) behave like that.

> In essence, the compiler should check and digest the generic code, like
> any other code, at the point where it is read. Thus, all properties of
> the components of T that affect the code interpretation must be explicit.
>
> This is roughly analogous to explicit interfaces for external
> procedures, which are recommended (but not enforced) in modern Fortran.
> Many problems of legacy applications originate from implicit
> interfaces of library procedures.
Agreed. The difference is that everything is explicit when the MODULE is instantiated/compiled.

/Espen

Wolfgang Kilian

unread,
Apr 16, 2015, 4:37:26 AM4/16/15
to
Yes, the compiler may choose to not compile the generic code at all,
wait until an instance is required. It would behave like a macro
preprocessor. But this is a problem: the instance compiles whenever the
compiler can make sense out of the resulting code. It can't check
whether the user of the generic code has followed the guidelines in the
documentation. Think of a mismatch between a function and an array
component: textually both make sense for the compiler, runtime behavior
will be different, but the program may run to completion.

I fear that this is no better than a library with a (correctly?)
documented but implicit interface. Errors may get through unnoticed a
long time. I'd avoid a macro-like facility in a compiled language,
unless it can check everything immediately.

>> It can give an interpretation only when it produces and compiles an
>> instance with a concrete realization of T. If the generic code is in an
>> external "template" library, the user of the library can't understand
>> the behavior of the an instance of the generic code, or compiler error
>> messages, without access to the source of the library. Even worse, if
>> implicit constraints are accidentally violated, an instance may compile
>> and run seamlessly but produce garbage results.
>>
> Any external library have to be documented in some way for the user to know which entities are defined within it etc., this would be no no different, e.g.:
> the type T must have components foo and i and a TBP named bar, and the bar procedure must have an interface like this and should (ideally, in order for the code to make sense) behave like that.

>> In essence, the compiler should check and digest the generic code, like
>> any other code, at the point where it is read. Thus, all properties of
>> the components of T that affect the code interpretation must be explicit.
>>
>> This is roughly analogous to explicit interfaces for external
>> procedures, which are recommended (but not enforced) in modern Fortran.
>> Many problems of legacy applications originate from implicit
>> interfaces of library procedures.
> Agreed. The difference is that everything is explicit when the MODULE is instantiated/compiled.
>
> /Espen
>

-- Wolfgang

Espen Myklebust

unread,
Apr 16, 2015, 10:15:34 AM4/16/15
to
On Thursday, April 16, 2015 at 10:37:26 AM UTC+2, Wolfgang Kilian wrote:
> > Wouldn't compiler have this information upon instantiation of the MODULE where this source code appears? The MODULE would not be compiled into object code until it is instantiated with an actual/concrete type... The "pattern" for the code would be stored in the .mod file which works as a precompiled header file (thank you FortranFan:). IMO this is no different from using a non-generic type: the compiler have to check at compile-time that it can resolve all the names ant that the program logic follows the rules of Fortran.
>
> Yes, the compiler may choose to not compile the generic code at all,
> wait until an instance is required. It would behave like a macro
> preprocessor. But this is a problem: the instance compiles whenever the
> compiler can make sense out of the resulting code. It can't check
> whether the user of the generic code has followed the guidelines in the
> documentation. Think of a mismatch between a function and an array
> component: textually both make sense for the compiler, runtime behavior
> will be different, but the program may run to completion.
>
How is this different that "normal" (i.e. non-generic) code? The compiler compiles what it can make sense out of, right?

As to the ambiguity of function references and array element designations: I find this to be a syntactic deficiency of the language and have proposed to the committee that we should allow the following syntax: array[subscript-list]
It could be a compiler option to require the proposed syntax.

> I fear that this is no better than a library with a (correctly?)
> documented but implicit interface. Errors may get through unnoticed a
> long time. I'd avoid a macro-like facility in a compiled language,
> unless it can check everything immediately.
>
Isn't all template mechanisms just glorified macros? You can do everything manually with INCLUDE as long as you have the source code; and as I understand it, all the "explicitness" (e.g. variable declarations, derived type definitions and procedure and interfaces) of MODULEs lie in the .mod files so that they are in some sense just another "form" of source code. You would need the information about the constraints to be stored somewhere too, and it would probably be the .mod files.

Wolfgang Kilian

unread,
Apr 16, 2015, 11:32:51 AM4/16/15
to
On 16.04.2015 16:15, Espen Myklebust wrote:
> On Thursday, April 16, 2015 at 10:37:26 AM UTC+2, Wolfgang Kilian wrote:
>>> Wouldn't compiler have this information upon instantiation of the MODULE where this source code appears? The MODULE would not be compiled into object code until it is instantiated with an actual/concrete type... The "pattern" for the code would be stored in the .mod file which works as a precompiled header file (thank you FortranFan:). IMO this is no different from using a non-generic type: the compiler have to check at compile-time that it can resolve all the names ant that the program logic follows the rules of Fortran.
>>
>> Yes, the compiler may choose to not compile the generic code at all,
>> wait until an instance is required. It would behave like a macro
>> preprocessor. But this is a problem: the instance compiles whenever the
>> compiler can make sense out of the resulting code. It can't check
>> whether the user of the generic code has followed the guidelines in the
>> documentation. Think of a mismatch between a function and an array
>> component: textually both make sense for the compiler, runtime behavior
>> will be different, but the program may run to completion.
>>
> How is this different that "normal" (i.e. non-generic) code? The compiler compiles what it can make sense out of, right?

The difference is in the 'when' and 'where'.

Suppose the generic code is in a library, like the C++ STL. Some other
programmer uses that library as a 'black box' at a later time. When,
how, and where will the compiler check for correctness?

> As to the ambiguity of function references and array element designations: I find this to be a syntactic deficiency of the language and have proposed to the committee that we should allow the following syntax: array[subscript-list]
> It could be a compiler option to require the proposed syntax.
>
>> I fear that this is no better than a library with a (correctly?)
>> documented but implicit interface. Errors may get through unnoticed a
>> long time. I'd avoid a macro-like facility in a compiled language,
>> unless it can check everything immediately.
>>
> Isn't all template mechanisms just glorified macros? You can do everything manually with INCLUDE as long as you have the source code; and as I understand it, all the "explicitness" (e.g. variable declarations, derived type definitions and procedure and interfaces) of MODULEs lie in the .mod files so that they are in some sense just another "form" of source code. You would need the information about the constraints to be stored somewhere too, and it would probably be the .mod files.

No, not at all. A template mechanism is an 'intelligent macro' - the
compiler checks everything already at the point of definition. This
requires all constraints on the generic objects that enter to be
well-defined and explicit. During macro expansion, the compiler checks
the concrete objects against the constraints. Conversely: with an
ordinary macro (plain INCLUDE, for instance), the compiler can check
only at the point of macro expansion. The set of explicit constraints
does the communication for a template, while for an ordinary macro the
constraints are implicit and can only be communicated by documentation.

There are borderline cases, of course. However, if the generic code
does simple things, constraints will also be simple, so why not write
them anyway?

>>>> It can give an interpretation only when it produces and compiles an
>>>> instance with a concrete realization of T. If the generic code is in an
>>>> external "template" library, the user of the library can't understand
>>>> the behavior of the an instance of the generic code, or compiler error
>>>> messages, without access to the source of the library. Even worse, if
>>>> implicit constraints are accidentally violated, an instance may compile
>>>> and run seamlessly but produce garbage results.
>>>>
>>> Any external library have to be documented in some way for the user to know which entities are defined within it etc., this would be no no different, e.g.:
>>> the type T must have components foo and i and a TBP named bar, and the bar procedure must have an interface like this and should (ideally, in order for the code to make sense) behave like that.
>>
>>>> In essence, the compiler should check and digest the generic code, like
>>>> any other code, at the point where it is read. Thus, all properties of
>>>> the components of T that affect the code interpretation must be explicit.
>>>>
>>>> This is roughly analogous to explicit interfaces for external
>>>> procedures, which are recommended (but not enforced) in modern Fortran.
>>>> Many problems of legacy applications originate from implicit
>>>> interfaces of library procedures.
>>> Agreed. The difference is that everything is explicit when the MODULE is instantiated/compiled.
>>>
>>> /Espen
>>>
>>
>> -- Wolfgang
>


Espen Myklebust

unread,
Apr 16, 2015, 3:23:23 PM4/16/15
to
On Thursday, April 16, 2015 at 5:32:51 PM UTC+2, Wolfgang Kilian wrote:
> On 16.04.2015 16:15, Espen Myklebust wrote:
> > On Thursday, April 16, 2015 at 10:37:26 AM UTC+2, Wolfgang Kilian wrote:
> >>> Wouldn't compiler have this information upon instantiation of the MODULE where this source code appears? The MODULE would not be compiled into object code until it is instantiated with an actual/concrete type... The "pattern" for the code would be stored in the .mod file which works as a precompiled header file (thank you FortranFan:). IMO this is no different from using a non-generic type: the compiler have to check at compile-time that it can resolve all the names ant that the program logic follows the rules of Fortran.
> >>
> >> Yes, the compiler may choose to not compile the generic code at all,
> >> wait until an instance is required. It would behave like a macro
> >> preprocessor. But this is a problem: the instance compiles whenever the
> >> compiler can make sense out of the resulting code. It can't check
> >> whether the user of the generic code has followed the guidelines in the
> >> documentation. Think of a mismatch between a function and an array
> >> component: textually both make sense for the compiler, runtime behavior
> >> will be different, but the program may run to completion.
> >>
> > How is this different that "normal" (i.e. non-generic) code? The compiler compiles what it can make sense out of, right?
>
> The difference is in the 'when' and 'where'.
>
> Suppose the generic code is in a library, like the C++ STL. Some other
> programmer uses that library as a 'black box' at a later time. When,
> how, and where will the compiler check for correctness?
>
I'm a bit uncertain that was a retoric question, but to be on the safe side I'll answer to the best of my ability :)
I'm no C(++) programmer (never written a line in my life) but I have read a bit about C++ templates and to my understanding a C++ template is usually put in its entirety in the header file which is then #include'ed. This is not the only option, as you can "pre-instantiate" a template into a concrete form in the library (the source code in a .cpp file) but then only the pre-instantiated realizations of the template will be available to the library user. Since this limits the flexibility of the library this is, as previously stated, not the most common strategy, but may be reasonable when you want this restriction. As long as the complete code is put in a header file it is (to my understanding) precompiled in some way and the compiler performs whatever checks it can at the time, but generally not enough to just "substitute in" the specified type during an instantiation. My impression is that the compiler has to do a reasonable amount of work for this, and it seems widely accepted that compiler error messages during instantiation are next to worthless (i.e. very cryptic).

> > As to the ambiguity of function references and array element designations: I find this to be a syntactic deficiency of the language and have proposed to the committee that we should allow the following syntax: array[subscript-list]
> > It could be a compiler option to require the proposed syntax.
> >
> >> I fear that this is no better than a library with a (correctly?)
> >> documented but implicit interface. Errors may get through unnoticed a
> >> long time. I'd avoid a macro-like facility in a compiled language,
> >> unless it can check everything immediately.
> >>
> > Isn't all template mechanisms just glorified macros? You can do everything manually with INCLUDE as long as you have the source code; and as I understand it, all the "explicitness" (e.g. variable declarations, derived type definitions and procedure and interfaces) of MODULEs lie in the .mod files so that they are in some sense just another "form" of source code. You would need the information about the constraints to be stored somewhere too, and it would probably be the .mod files.
>
> No, not at all. A template mechanism is an 'intelligent macro' - the
> compiler checks everything already at the point of definition. This
This sounds like generics in Ada (that I know just a tiny bit about (not meant as an understatement)) which seems quite a bit more restrictive than C++ templates
> requires all constraints on the generic objects that enter to be
> well-defined and explicit. During macro expansion, the compiler checks
> the concrete objects against the constraints. Conversely: with
> ordinary macro (plain INCLUDE, for instance), the compiler can check
> only at the point of macro expansion. The set of explicit constraints
> does the communication for a template, while for an ordinary macro the
> constraints are implicit and can only be communicated by documentation.
>
How are the constraints communicated to the compiler of the library user? There must be some file somewhare that the compiler reads to find these??
And how are the constraints communicated to the user? by some other means than documentation??

I think what I struggle with is to understand is what you mean be compiling a generic MODULE... Is there any object code generated? It seems strange since there is (by the definition of generic programming) no actual/explicit types available at that time, right..? Of course there can be (i.e. what I called "pre-instantiated" before), but that is a restricted case (although far from useless!).

Wolfgang Kilian

unread,
Apr 17, 2015, 3:00:27 AM4/17/15
to
On 16.04.2015 21:23, Espen Myklebust wrote:
> On Thursday, April 16, 2015 at 5:32:51 PM UTC+2, Wolfgang Kilian wrote:
>> On 16.04.2015 16:15, Espen Myklebust wrote:
>>> On Thursday, April 16, 2015 at 10:37:26 AM UTC+2, Wolfgang Kilian wrote:
>>>>> Wouldn't compiler have this information upon instantiation of the MODULE where this source code appears? The MODULE would not be compiled into object code until it is instantiated with an actual/concrete type... The "pattern" for the code would be stored in the .mod file which works as a precompiled header file (thank you FortranFan:). IMO this is no different from using a non-generic type: the compiler have to check at compile-time that it can resolve all the names ant that the program logic follows the rules of Fortran.
>>>>
>>>> Yes, the compiler may choose to not compile the generic code at all,
>>>> wait until an instance is required. It would behave like a macro
>>>> preprocessor. But this is a problem: the instance compiles whenever the
>>>> compiler can make sense out of the resulting code. It can't check
>>>> whether the user of the generic code has followed the guidelines in the
>>>> documentation. Think of a mismatch between a function and an array
>>>> component: textually both make sense for the compiler, runtime behavior
>>>> will be different, but the program may run to completion.
>>>>
>>> How is this different that "normal" (i.e. non-generic) code? The compiler compiles what it can make sense out of, right?
>>
>> The difference is in the 'when' and 'where'.
>>
>> Suppose the generic code is in a library, like the C++ STL. Some other
>> programmer uses that library as a 'black box' at a later time. When,
>> how, and where will the compiler check for correctness?
>>
> I'm a bit uncertain that was a retoric question, but to be on the safe side I'll answer to the best of my ability :)
> I'm no C(++) programmer (never written a line in my life) but I have read a bit about C++ templates and to my understanding a C++ template is usually put in its entirety in the header file which is then #include'ed. This is not the only option, as you can "pre-instantiate" a template into a concrete form in the library (the source code in a .cpp file) but then only the pre-instantiated realizations of the template will be available to the library user. Since this limits the flexibility of the library this is, as previously stated, not the most common strategy, but may be reasonable when you want this restriction. As long as the complete code is put in a header file it is (to my understanding) precompiled in some way and the compiler performs whatever checks it can at the time, but generally not enough to just "substitute in" the specified type during an instantiation. My impression is that the compiler has to do a reasonable amount of work for this, and it seems widely accepted that
compiler error messages during instantiation are next to worthless (i.e. very cryptic).
>

Yes, and I'm also far from being a C++ programmer. If cryptic error
messages at instantiation do occur, this sounds to me like an inherent
deficiency that should be avoided by proper language design. The C++
designers are not to blame, this is already decades old. It should be
possible to gain from that experience, however.

>>> As to the ambiguity of function references and array element designations: I find this to be a syntactic deficiency of the language and have proposed to the committee that we should allow the following syntax: array[subscript-list]
>>> It could be a compiler option to require the proposed syntax.
>>>
>>>> I fear that this is no better than a library with a (correctly?)
>>>> documented but implicit interface. Errors may get through unnoticed a
>>>> long time. I'd avoid a macro-like facility in a compiled language,
>>>> unless it can check everything immediately.
>>>>
>>> Isn't all template mechanisms just glorified macros? You can do everything manually with INCLUDE as long as you have the source code; and as I understand it, all the "explicitness" (e.g. variable declarations, derived type definitions and procedure and interfaces) of MODULEs lie in the .mod files so that they are in some sense just another "form" of source code. You would need the information about the constraints to be stored somewhere too, and it would probably be the .mod files.
>>
>> No, not at all. A template mechanism is an 'intelligent macro' - the
>> compiler checks everything already at the point of definition. This
> This sounds like generics in Ada (that I know just a tiny bit about (not meant as an understatement)) which seems quite a bit more restrictive than C++ templates

Yes, and other strongly-typed languages also have facilities of this kind.

>> requires all constraints on the generic objects that enter to be
>> well-defined and explicit. During macro expansion, the compiler checks
>> the concrete objects against the constraints. Conversely: with
>> ordinary macro (plain INCLUDE, for instance), the compiler can check
>> only at the point of macro expansion. The set of explicit constraints
>> does the communication for a template, while for an ordinary macro the
>> constraints are implicit and can only be communicated by documentation.
>>
> How are the constraints communicated to the compiler of the library user? There must be some file somewhare that the compiler reads to find these??
> And how are the constraints communicated to the user? by some other means than documentation??

C++ uses headers (human-readable, standardized), most Fortran compilers
generate .mod files (automatic, not mentioned in the standard). One can
imagine that .mod files contain complete information about the interface
and explicit constraints of any generic code, so the compiler takes that
info and checks code provided by the library user against it, before
final compilation/optimization. There is no conceptual difference to
Fortran's usual type- and interface-checking.

>
> I think what I struggle with is to understand is what you mean be compiling a generic MODULE... Is there any object code generated? It seems strange since there is (by the definition of generic programming) no actual/explicit types available at that time, right..? Of course there can be (i.e. what I called "pre-instantiated" before), but that is a restricted case (although far from useless!).

That's up to the compiler. Generic modules, or modules with generic
code involved, compiled or interpreted, are a well-known concept, just
not in Fortran. A safe setup is definitely possible.

-- Wolfgang

Espen Myklebust

unread,
Apr 17, 2015, 6:49:20 AM4/17/15
to
I guess that with an interpreted (read: dynamically typed) language you wouldn't even call it generic programming, just programming ;)
I don't think generic code is unknown to users of Fortran, there is just no mechanism for handling it built into the language so you're stuck with INCLUDE (or other methods?); but that may not qualify as generic programming by everyone.
I don't think we disagree on anything, although I have not yet a good understanding of what you mean by compiling source code that is not fully specified (in terms of types for instance) and how a user would know more about a library if the source code had some extra information (that is provided to the compiler and not necessarily available to the user) of what to require from a type that is to be used in an instantiation/realization of a MODULE.
In C++ there was a proposal of something called "Concepts" for C++11, and I think this might be close to what you describe; the wikipedia article on the topic says its motivation is primarily "to improve the quality of compiler error messages" which of course is important, but as far as I can tell there is not much difference as to what the compiler does which is still to compile code as it is/was parsed. My impression is that the "Concepts" added very much complexity and that many extra lines of code would have to be written in order to use it at all. This might not be the case if it was to be included into Fortran since it differs substantially from C++ wrt. complexity.

edmondo.g...@gmail.com

unread,
Apr 17, 2015, 8:45:55 AM4/17/15
to

Well, I used C++ some years ago in a project, and the error messages where really a nightmare, typically because you passed a non constant in a place where a const was expected.

The STL were really amazing, and also the generic programming. The STL were actually only include files (at least, it was what I thought, but I'm not an expert).
So that, for example, a comparison between two objects (a < b) in a templated function could become a simple numerical, (and fast) comparison if the two objects were standard numerical types. On the other hand if the two objects were complex objects a dedicated subroutine could have been called. So no performance penalty.

I remember about some rules that if you want to use on object in a container that object should have some specific methods available, and a lots of error messages if that wasn't true...

By the way it was an interesting excursus in a different language, I have always programmed in Fortran and now also in Python.


Ian Harvey

unread,
Apr 17, 2015, 11:27:22 PM4/17/15
to
On 2015-04-15 6:23 PM, Stefano Zaghi wrote:

> Do you like the idea of FortranFan et al.?

I have been away for a few days, and else-thread the discussion has
progressed, but I think Wolfgang has already expressed most of the
conceptual capabilities that I would like to see in a generic
programming enhancement to Fortran, particularly around the need to be
able to describe in-source the requirements that my generic code might
have on the client types and procedures that it might work on, such that
when I, as a client programmer, fail to meet those requirements, the
processor can effectively help me fix my mistake.

One point that might not have been raised though - I'm not so sure that
the best approach to parameterisation is at the type level - i.e as we
have now with kind and length parameters. With the language as it is,
it may be more effective if parameterisation was done at the module and
submodule level. Coming at it from the perspective of a library author
writing generic code - you typically want to provide a *package* of
types (plural), procedures and perhaps variables to the clients of your
library, that all have a common compile time parameterisation. The
current means of packaging code in Fortran is a module.

This is in the context of the current design of the language compared
with other languages - particularly that procedures are not members of a
type.

This is motivated in part by my experience with kind type parameters in
F2003, compared with length type parameters. I find kind type
parameters of marginal use in their current form in the current language
- you pretty much have to know at the time that you write the type and
its accompanying procedures the singular "value" of the kind parameter
(which might be specified by a named constant) that you will support.
You can easily parameterise the type, but not the procedures that use
the type - all the kind parameterisation is offering you is some
namespace nicety. On the other hand, with length parameters, you can
provide in a package both a type and procedures that will support
multiple values of the length parameter with the one chunk of code.

I'd also like to see the ability to parameterise modules for aspects
other than type - integer parameterisation for example.

As a parallel feature, you may also want to have type based
parameterisation of types and type and integer parameterisation of
procedures. Integer parameterisation of procedures would go a long way
towards resolving the current issues with kind type parameters.

For parameterised procedures, I think I favour explicit instantiation
(this identifier is this parameterised procedure instantiated with these
parameters), rather than the implicit instantiation (look at the
arguments, try and work out what parameter values result in a valid call).

Other aspects to consider include whether parameter that is a type is
just a type, a type spec (i.e. with type parameters), or a declaration
type spec (CLASS/TYPE); for procedures whether you can parameterise out
attributes such as argument INTENT (c.f. const versus non-const
parameterisation in C++); if a module is parameterised under what
conditions are module variables considered unique instances; can you
parameterise out rank; should there be the capability for specialisation
and incomplete specialisation, etc, etc, etc, etc...

I've played with some options for implementation of some of these
features, but haven't got very far.

FortranFan

unread,
Apr 18, 2015, 9:38:46 AM4/18/15
to
Perhaps it is time for those with good understanding of the needs and with some knowledge of compilers and other language implementations (Ada?) to start making some formal proposals for generic programming along the lines of what Van Snyder has done with exception handling in Fortran in the latest issue of ACM Fortran Forum (http://dl.acm.org/citation.cfm?id=2754943&CFID=665080277&CFTOKEN=31947854).

Wolfgang Kilian

unread,
Apr 18, 2015, 10:08:37 AM4/18/15
to
I have always wondered why there are intrinsic procedures with kind
parameters, but no user-defined ones. I didn't try yet, but how should
I define methods (TBP) for a kind-parameterized type?

> I'd also like to see the ability to parameterise modules for aspects
> other than type - integer parameterisation for example.
>
> As a parallel feature, you may also want to have type based
> parameterisation of types and type and integer parameterisation of
> procedures. Integer parameterisation of procedures would go a long way
> towards resolving the current issues with kind type parameters.

I agree with all of this. I can see an opportunity to have both
library-scale generic-code support via parameterized modules and
small-scale generic-code support via parameterized types and procedures.
(Modules do have management overhead in terms of Makefile entries,
etc.) It should be possible to pick up loose ends in the language, so
no fundamentally different syntax is required, and the new features act
complementing each other. For a compiled language, generics
(compile-time resolved) can only add in usability, there is no runtime
penalty involved.

>
> For parameterised procedures, I think I favour explicit instantiation
> (this identifier is this parameterised procedure instantiated with these
> parameters), rather than the implicit instantiation (look at the
> arguments, try and work out what parameter values result in a valid call).
>
> Other aspects to consider include whether parameter that is a type is
> just a type, a type spec (i.e. with type parameters), or a declaration
> type spec (CLASS/TYPE); for procedures whether you can parameterise out
> attributes such as argument INTENT (c.f. const versus non-const
> parameterisation in C++); if a module is parameterised under what
> conditions are module variables considered unique instances; can you
> parameterise out rank; should there be the capability for specialisation
> and incomplete specialisation, etc, etc, etc, etc...
>
> I've played with some options for implementation of some of these
> features, but haven't got very far.

An experimental implementation of generics would be interesting to play
with -- via preprocessor? I also had ideas about writing something, but
it looks like one needs at least a kind of Fortran syntax parser to
start with.

-- Wolfgang

Wolfgang Kilian

unread,
Apr 18, 2015, 10:25:36 AM4/18/15
to
On 04/18/2015 03:38 PM, FortranFan wrote:

>
>
> Perhaps it is time for those with good understanding of the needs and with some knowledge of compilers and other language implementations (Ada?) to start making some formal proposals for generic programming along the lines of what Van Snyder has done with exception handling in Fortran in the latest issue of ACM Fortran Forum (http://dl.acm.org/citation.cfm?id=2754943&CFID=665080277&CFTOKEN=31947854).
>

It looks like some of the more interesting content in this newsgroup is
restricted to ACM members ...

-- Wolfgang


0 new messages