Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.

TYPE IS guard for multiple kinds

holysword
Novice
645 Views

Is it possible to write a TYPE IS guard for an unlimited polymorphic class, but that matches the type regardless of the kind (for intrinsic types only, naturally). For instance

CLASS(*), INTENT(IN) :: my_int

SELECT TYPE(my_int)
   TYPE IS(INTEGER(KIND=*))
      PRINT *,"This is an integer, but I don't know which kind!"
   CLASS DEFAULT
      PRINT *,"Nope, not an integer"
END SELECT

Does Fortran 2008 allow any trick to treat this case or do I have to actually copy and paste the same statement block for every single kind of integer?

Thanks in advance!

0 Kudos
1 Solution
FortranFan
Honored Contributor II
645 Views

holysword wrote:

.. I was afraid that it was not possible to do anything other than preprocessor magic to prevent duplication of the code.

What I was trying to do was to use CLASS(*) to avoid having a different subroutine for each kind. They all are supposed to manipulate the numbers (both integer and real) in the same way, just the precision of the input and output will change according to the kind.

@holysword,

You're right: other than the use of a preprocessor, one is forced to duplicate code to a considerable extent.  Unfortunately current Fortran standard appears deficient (at least to me) in generics which is what you are seeking.

Say you want to write a 'swap' procedure to swap two parameters, a and b, for different types, integer(4), real(4), etc.  There is no reasonably efficient, concise way to do so using current standard Fortran: whatever standard options one might use - polymorphism, include files, etc. all appear clunky.  Even the use of preprocessors can be tricky: once Intel Fortran starts supporting the Fortran 2008 feature that allows TYPE statement for intrinsic types, it can become easier.  So you're left with having to duplicate a whole lot of code.

Steve,

Building on some discussions on the topic of generics, it'll be nice if Intel representatives on the Fortran standard committee can make a note of this thread and other similar ones to eventually work toward improved support for generics in Fortran 20XY i.e., whenever the standard extension process commences following the Fortran 2015 standard.  For the above-mentioned 'swap' case, if the standard can start provide support along the following lines, it will serve the coders very well:

! 'pseudo' code: not supported by current Fortran standard
module m
   
   implicit none
   
   !.. Builds on Fortran 2015 syntax for Generics
   generic :: type(t) => integer(4), integer(8), real(4), real(8)
   
contains

   subroutine swap(a, b)
      
      ! 't' from host association; can come from USE statement
      type(t), intent(inout)       :: a   !.. Note Fortran 2008 introduced type(integer(4)), type(real), syntax 
      type(type(a)), intent(inout) :: b   !   A new aspect that borrows from support for KIND in current standard 
      
      !.. Local variables
      type(type(a)) :: temp
      
      temp = a
      a = b
      b = temp
      
      return
      
   end subroutine swap
   
end module m

Note I'm not trying to offer a specific solution, simply putting forth some cases that might help steer the discussion.  The point is Fortran needs to offer far better support for generics, something that will be at least on par with what is provided by other languages which are being used in same or similar application domains as Fortran e.g., Ada, C++, C#, Java, etc. for numeric/technical/engineering/scientific computing. 

As to how a compiler might support such extended support for generics, I do not know.  But I assume it will involve preprocessing, creating extra code, multiple compilation passes, etc. and that none of this should be all that difficult for Intel Fortran.

View solution in original post

0 Kudos
8 Replies
Steven_L_Intel1
Employee
645 Views

As far as I know, there isn't a way to do this. Within a TYPE IS block, the selector has a specific type and kind. What exactly are you trying to do here?

0 Kudos
holysword
Novice
646 Views

Steve Lionel (Intel) wrote:

As far as I know, there isn't a way to do this. Within a TYPE IS block, the selector has a specific type and kind. What exactly are you trying to do here?

Hello Steve Lionel,

Thank you for your reply. I was afraid that it was not possible to do anything other than preprocessor magic to prevent duplication of the code.

What I was trying to do was to use CLASS(*) to avoid having a different subroutine for each kind. They all are supposed to manipulate the numbers (both integer and real) in the same way, just the precision of the input and output will change according to the kind.

0 Kudos
FortranFan
Honored Contributor II
646 Views

holysword wrote:

.. I was afraid that it was not possible to do anything other than preprocessor magic to prevent duplication of the code.

What I was trying to do was to use CLASS(*) to avoid having a different subroutine for each kind. They all are supposed to manipulate the numbers (both integer and real) in the same way, just the precision of the input and output will change according to the kind.

@holysword,

You're right: other than the use of a preprocessor, one is forced to duplicate code to a considerable extent.  Unfortunately current Fortran standard appears deficient (at least to me) in generics which is what you are seeking.

Say you want to write a 'swap' procedure to swap two parameters, a and b, for different types, integer(4), real(4), etc.  There is no reasonably efficient, concise way to do so using current standard Fortran: whatever standard options one might use - polymorphism, include files, etc. all appear clunky.  Even the use of preprocessors can be tricky: once Intel Fortran starts supporting the Fortran 2008 feature that allows TYPE statement for intrinsic types, it can become easier.  So you're left with having to duplicate a whole lot of code.

Steve,

Building on some discussions on the topic of generics, it'll be nice if Intel representatives on the Fortran standard committee can make a note of this thread and other similar ones to eventually work toward improved support for generics in Fortran 20XY i.e., whenever the standard extension process commences following the Fortran 2015 standard.  For the above-mentioned 'swap' case, if the standard can start provide support along the following lines, it will serve the coders very well:

! 'pseudo' code: not supported by current Fortran standard
module m
   
   implicit none
   
   !.. Builds on Fortran 2015 syntax for Generics
   generic :: type(t) => integer(4), integer(8), real(4), real(8)
   
contains

   subroutine swap(a, b)
      
      ! 't' from host association; can come from USE statement
      type(t), intent(inout)       :: a   !.. Note Fortran 2008 introduced type(integer(4)), type(real), syntax 
      type(type(a)), intent(inout) :: b   !   A new aspect that borrows from support for KIND in current standard 
      
      !.. Local variables
      type(type(a)) :: temp
      
      temp = a
      a = b
      b = temp
      
      return
      
   end subroutine swap
   
end module m

Note I'm not trying to offer a specific solution, simply putting forth some cases that might help steer the discussion.  The point is Fortran needs to offer far better support for generics, something that will be at least on par with what is provided by other languages which are being used in same or similar application domains as Fortran e.g., Ada, C++, C#, Java, etc. for numeric/technical/engineering/scientific computing. 

As to how a compiler might support such extended support for generics, I do not know.  But I assume it will involve preprocessing, creating extra code, multiple compilation passes, etc. and that none of this should be all that difficult for Intel Fortran.

0 Kudos
Steven_L_Intel1
Employee
646 Views

I have heard quite a few requests for generics. I will certainly suggest that this be considered in the "work plan" for the next standard. I would take issue with "none of it will be all that difficult" and I'll caution that the more you abstract, the harder the compiler's job is and the lower the performance.

0 Kudos
FortranFan
Honored Contributor II
646 Views

Steve Lionel (Intel) wrote:

I have heard quite a few requests for generics. I will certainly suggest that this be considered in the "work plan" for the next standard. I would take issue with "none of it will be all that difficult" and I'll caution that the more you abstract, the harder the compiler's job is and the lower the performance.

Thanks Steve.

Please ignore my other comment about "none .. difficult" - it is not really germane to this discussion.

But on your response on performance, I'll note:

  1. At the same level of abstraction, code in Fortran should perform nearly as well as C++, if not more.  What I mean is as follows.  Say if one follows a procedural programming style in standard C++ for some task, e.g., matrix operations, and has performance X with Intel C++ compiler and the same task with standard Fortran has performance X' with Intel Fortran compiler (hopefully X' is much better than X, but that's not relevant here).  Now if the C++ code is abstracted in object-oriented (OO) style using some well-established, efficient OO paradigm [e.g., it may be structures-of-arrays (SoA) instead of arrays-of-structures (AoS)] and has performance Y (which may be poorer than X due to abstraction overhead), the relative change is Y/X.  Now if one does the same with standard Fortran using OO features introduced since Fortran 2003 standard and gets a performance of Y' using Intel Fortran, then I think customers can legitimately expect the relative change of Y'/X' to be approximately similar to Y/X; if it's better, then wonderful.  Now if that is not the case, meaning abstraction in Fortran results in much larger performance degradation even when good abstraction paradigms and patterns are followed, then someone from Intel Fortran compiler team should be able to point out why that is the case and perhaps even provide some guidance to users to improve performance.  If not, that's a great disservice to Fortran users who are trying to adopt modern programming practices.  So what I'm trying to convey is many of the abstraction paradigms and idioms utilized in numeric/technical/scientific computing have been vetted using C++ and users in these domains have conceded some performance degradation while gaining other benefits of abstraction.  Fortran users can accept a similar penalty in performance due to abstraction, but the users will be ill-served if they have to pay a far greater penalty than commensurate changes in C++, etc..
  2. Now note in cases where run-time polymorphism and dynamic dispatch, etc. are not involved, meaning when TKR information, etc. are fully resolved at compile time, as would be the case with 'swap' example I gave in my previous note, users will accept that compilation complexity will now be higher and compilation times will be longer, but there should be no run-time performance difference.  Just like ABS(A) and DABS(A) for double precision A gets resolved to the right intrinsic function to yield same performance, swap(foo, bar), assuming foo, bar are real(8), should work the same as a specific procedure for real(8) arguments e.g, swap_r8.  Meaning the abstraction for the specific 'swap' example I gave is at compilation level, not run-time.  So there should be no run-time performance degradation.  If you disagree on this, then it will be very useful to us readers to know why.
0 Kudos
Steven_L_Intel1
Employee
646 Views

I'd want to see some concrete proposals before trying to comment in detail. I refreshed my memory about Ada generics, as I trust the Ada model more than C++. I can imagine several implementation models, but to be practical it would have to leverage the existing compiler's structure. I'm sure it will get a good thrashing out in the committee.

Are you interested in joining the committee and contributing to the effort?

0 Kudos
holysword
Novice
646 Views

FortranFan wrote:

  1. Now note in cases where run-time polymorphism and dynamic dispatch, etc. are not involved, meaning when TKR information, etc. are fully resolved at compile time, as would be the case with 'swap' example I gave in my previous note, users will accept that compilation complexity will now be higher and compilation times will be longer, but there should be no run-time performance difference.  Just like ABS(A) and DABS(A) for double precision A gets resolved to the right intrinsic function to yield same performance, swap(foo, bar), assuming foo, bar are real(8), should work the same as a specific procedure for real(8) arguments e.g, swap_r8.  Meaning the abstraction for the specific 'swap' example I gave is at compilation level, not run-time.  So there should be no run-time performance degradation.  If you disagree on this, then it will be very useful to us readers to know why.

For Fortran specifically, I always assume that this is "the right thing to do", that is, to burden the compilation time rather than execution time. The only thing that worries me is that people may abuse it and generate considerably larger codes. Just imagine a function receiving X INTEGER arguments with generic kinds. What would the compiler do? Replicate the function for each possible permutation of inputs? If 4 integer kinds are considered, that makes 4^X possible permutations, so it is easy to see how this could run out of control. Also, in many cases you'd expect all the X integers to be of the same generic kind, and not of different kinds. In addition to that, I get headaches when I try to imagine what would happen with functions inlining.

Anyway, good to see that the generic programming topic is still relevant in the Fortran committee.

0 Kudos
Steven_L_Intel1
Employee
646 Views

The typical approach is that while you write the "generic" code once, you have to instantiate each combination you want. The compiler isn't supposed to automatically create every possible combination, however it does need to add to its generic list each of the specific procedures you create. In this sense it's like parameterized derived types with KIND parameters. - you declare the type once but have to say which KIND you want each time you use it in a declaration.

What would have to happen is that the compiler keeps around some sort of parse tree of the generic routine with types that get filled in each time you create a new specific variant. It gets messy because in some cases parsing requires that you know exactly which type an identifier is.

0 Kudos
Reply