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

Generic pointer alias to another pointer

AThar2
Beginner
404 Views

I don't know how to reference what I am trying to do, but here is the explanation of what I desire to do.

 

In one module file "mod1.f" I have defined the following type

 

 

type md_typ1 

   real, pointer, contiguous :: x1(:) 
   integer, pointer, contiguous :: i1(:) 

   real, pointer, contiguous :: x11  ! no rank
   integer, pointer, contiguous :: i11 ! no rank

end type 

 

These pointer need to be an alias of a section of a buffer. Each of these pointers have an associated defined name as characters.

This allows me then to do the following in a different module file:

if( input_name == 'x1') typ1% x1 => buf(i1:i2) 

 

 

I want it to be a bit more generic, where I in mod1 define a subroutine that returns one of the pointers in md_typ1, so we instead can do:

 

call GIVE_ME_POINTER( input_name, ptr_corresponding_to_input_name)

ptr_corresponding_to_input_name => buf(i1:i2) ! assume here that input_name is x1 and hence the ptr_corresponding_to_input_name should have been associated to typ1% x1

 

I got two issues here:

1) Is it correct to assume (if everything done correctly) that `ptr_corresponding_to_input_name` is implicitly updating my `typ1% x1` - so EVEN THOUGH `ptr_corresponding_to_input_name` GOES OUT OF SCOPE, `typ1% x1` is still referencing to `buf(i1:i2)` ??

 

2) How do I make such a routine that can return the pointer generic. My attempts is the following

 

 

subroutine GIVE_ME_POINTER( name_str, ptr_out) 

character(len=*), intent(in) :: name_str
class(*), intent(out) :: ptr_out


select case(name_str) 

    case('x1') 
       ptr_out => typ1% x1 
    case('i1')
       ptr_out => typ1% i1 
 !etc etc 

end select

end subroutine

 

 

Is that legal in Fortran , especially w.r.t the use of class(*)

 

Thanks in advance,

 

 

 

 

 

0 Kudos
9 Replies
FortranFan
Honored Contributor II
404 Views

You may want to consider overloaded methods i.e., generic interfaces to specific procedures, as suggested to you in a previous thread:

https://software.intel.com/en-us/forums/intel-fortran-compiler-for-linux-and-mac-os-x/topic/808788

Given the limitations at present with generics in Fortran and what the Fortran standard states about dummy arguments of unlimited polymorphic type - CLASS(*) [and a somewhat related TYPE(*)] - generic interfaces to specific procedures is a sound approach though it may require more repetitive code but which can be addressed using INCLUDE facility even if INCLUDEs are seen as old-fashioned.

 

0 Kudos
AThar2
Beginner
404 Views

Hello @FortranFan, 

 

I wanted to avoid overloaded methods in this case - and since I am not allocating as such I thought it could be of use here? But I am struggling to know where and where not it makes sense/appropriate to employ the class(*) features.

 

Is it possible to say  if my subroutine GIVE_ME_POINTER is valid and why not (in case it is not)?

0 Kudos
AThar2
Beginner
404 Views

Just to add: The compiler accepts the routine (ifort v19.0.3). The question is though whether I am doing something dangerous?

0 Kudos
FortranFan
Honored Contributor II
404 Views

@AT90,

I think what you will notice if you proceed further as you have tried with 19.0.3 is the value of your 'GIVE_ME_POINTER' will be rather limited or even useless.  You will find it work with unlimited polymorphic actual arguments only and if you construct objects of such type in your calling code, SELECT TYPE constructs will be necessary to work with those objects, leading to verbose, clunky code.

CLASS(*) facility in Fortran mostly helps "hold" data of any type, but its use in working with data of any type such as with 'generic' dummy arguments is rather limited and often counter-productive or even dangerous.

As you were suggested before, you can review references in Dr Fortran blog https://software.intel.com/en-us/blogs/2013/12/30/doctor-fortran-in-its-a-modern-fortran-world for more formal, thorough treatment of such details than is possible in a forum thread.  These references can even guide you toward better design of your data structures using object-oriented philosophy which can then be combined with several features involving type-bound procedures starting Fortran 2003; a variable with POINTER attribute in any variable definition context starting Fortran 2008, etc. - with Intel Fortran providing good support for these - to achieve what you imply in your original post.  But use POINTER attributes in Fortran only if absolutely necessary; try your hardest to avoid them; or at least strive to minimize their instances to few places in code.  Note there is a strong element of creative architectural design to all this and it's almost impossible to convey all details in a forum post.  You may find it better to 'review' available references and put your 'creative' hat on to design your code.

0 Kudos
AThar2
Beginner
404 Views

@FortranFan,

What you mention about class(*) is why I thought I could use at that very instance. Because, I only need the unlimited polymorphic to assign a global pointer to the correct place, and then I don't care about that unlimited pointer any longer. So when I return the unlimited pointer, it is return to the caller which has an explicit declaration of that retuned pointer i.e. 

 

The caller section 

 

subroutine AA

implicit none 

real, pointer :: aux(:) 

call GIVE_ME_POINTER( 'x1', aux) 

aux => global_buff(1:100) 

end subroutine 

Now the idea is that the routine ´GIVE_ME_POINTER´ has pointed my aux pointer to the typ1% x1 pointer. So if access typ1% x1(1:100) should be equal to global_buff(1:100)

 

Regarding you comment on use of pointer:

I have been told using pointers should be avoided when necessary. But to justify my use in this case, and I would appreciate your opinion because this choice is a critical part of my code.

I have a set of variables that I am communicating with MPI, hence, it is more efficient to put them on one big buffer to do the communication at one MPI call. So I am allocating this big buffer, and having aliases (pointers) to the section of the buffer which corresponds to the different variables e.g. 

x1 => buf(1:100), u1=> buf(101:200) 

In that way I can operate with x1 and u1 and directly do the MPI call with respect to buf without bothering about copying my variables into the buffer etc. Does its use make sense?

0 Kudos
FortranFan
Honored Contributor II
404 Views

AT90 wrote:

.. So when I return the unlimited pointer, it is return to the caller which has an explicit declaration of that retuned pointer i.e. 

The caller section 

 

subroutine AA

implicit none 

real, pointer :: aux(:) 

call GIVE_ME_POINTER( 'x1', aux) 

aux => global_buff(1:100) 

end subroutine 

..

As I mentioned earlier, the Fortran standard essentially requires the actual argument to be unlimited polymorphic when the dummy argument is unlimited polymorphic with the POINTER (or ALLOCATABLE) attribute.  So you will need "class(*), pointer :: aux(:)' for the call to GIVE_ME_POINTER to conform.

Separately, in this snippet you show, the 'call GIVE_ME_POINTER(' statement appears superfluous, what pointer assignment in that procedure being undone by the pointer assignment 'aux => global_buff(1:100)'

AT90 wrote:

.. 

I have a set of variables that I am communicating with MPI, hence, it is more efficient to put them on one big buffer to do the communication at one MPI call. So I am allocating this big buffer, and having aliases (pointers) to the section of the buffer which corresponds to the different variables e.g. 

x1 => buf(1:100), u1=> buf(101:200) 

In that way I can operate with x1 and u1 and directly do the MPI call with respect to buf without bothering about copying my variables into the buffer etc. Does its use make sense?

 

Is it really the case you need some solution for book-keeping (rather than a 'generic' pointer association procedure), say one that manages indices such as 1 and 100 with your global data buffer for use with your 'x1' alias and 101 and 200 with 'u1' alias?

By the way, Fortran is type-safe and technically there is no standard-conforming way to have a single global buffer, a blob of memory, that can hold data of different types, real/integer. etc.  There are non-standard options that have been used in FORTRAN programs for long, but it's difficult to work with them and may suffer issues on different platforms, compiler versions, etc.  You may want to cross-check what you are trying with MPI with respect to standard conformance (e.g., /stand with Intel Fortran and -std= option with gfortran) if that is important to you.

0 Kudos
AThar2
Beginner
404 Views

Separately, in this snippet you show, the 'call GIVE_ME_POINTER(' statement appears superfluous, what pointer assignment in that procedure being undone by the pointer assignment 'aux => global_buff(1:100)'

I am not sure I understand what you mean here?

 

Is it really the case you need some solution for book-keeping (rather than a 'generic' pointer association procedure), say one that manages indices such as 1 and 100 with your global data buffer for use with your 'x1' alias and 101 and 200 with 'u1' alias?

The short answer is yes, I just have many. That is why I wanted a routine to return the correct global pointer, which is pointing to the righ chunk of the global memory.

 

By the way, Fortran is type-safe and technically there is no standard-conforming way to have a single global buffer, a blob of memory, that can hold data of different types, real/integer. etc.  There are non-standard options that have been used in FORTRAN programs for long, but it's difficult to work with them and may suffer issues on different platforms, compiler versions, etc.  You may want to cross-check what you are trying with MPI with respect to standard conformance (e.g., /stand with Intel Fortran and -std= option with gfortran) if that is important to you.

I am not having different types in one buffer. I have different buffers for different types. I don't think it is wise to try to mix these different kinds either. 

 

0 Kudos
FortranFan
Honored Contributor II
404 Views

AT90 wrote:

.. I am not sure I understand what you mean here?

If the call to that subprogram is immediately followed by 'aux => global_buff(1:100)' statement, the end result will be the same whether you made a call to that subroutine or not.  Did you mean a data assignment with "equal to" symbol instead of pointer assignment? i.e., aux = ..

AT90 wrote:

.. The short answer is yes, I just have many. That is why I wanted a routine to return the correct global pointer, which is pointing to the righ chunk of the global memory. ..

As I implied earlier, you can achieve this in various ways with varying degrees of success, sophistication, complexity, and/or performance with Fortran.  Questions really pertain to your needs and requirements.  If you can put together a simple working prototype program of data management handling with, say, 2 sets of data, one REAL and the other INTEGER arrays associated with some global buffer(s) to be used with MPI, readers can suggest options for you.  Without some additional details on your data structure, I would struggle to suggest anything further.

0 Kudos
AThar2
Beginner
404 Views

If the call to that subprogram is immediately followed by 'aux => global_buff(1:100)' statement, the end result will be the same whether you made a call to that subroutine or not.  Did you mean a data assignment with "equal to" symbol instead of pointer assignment? i.e., aux = ..

Ohh I see, yes that is non sensical. I should probably be saying 'aux = global_buff(1:100)' immidieatly after the call to my routine. Would that mean that the global pointer 'typ1% x' is now pointing to  'lobal_buff(1:100)'. 

If not, Could I then do it the other way around i.e. 

aux => global_buff(1:100)

call SET_POINTER(aux, 'x1') 

 where SET_POINTER would instead be assigning ´typ1% x = aux'?

Perhaps both approaches are equally valid? 

 

As I implied earlier, you can achieve this in various ways with varying degrees of success, sophistication, complexity, and/or performance with Fortran.  Questions really pertain to your needs and requirements.  If you can put together a simple working prototype program of data management handling with, say, 2 sets of data, one REAL and the other INTEGER arrays associated with some global buffer(s) to be used with MPI, readers can suggest options for you.  Without some additional details on your data structure, I would struggle to suggest anything further.

I will try to work out a simple prototype. But I will probably need to think carefully how to make consise and yet representable. The difficulty is because I am trying to implement various communication methods, one of which does not require a buffer (it is a shared memory approach with mpi , it does not reuiqre a buffer). For me to keep it as generic where I still can keep using 'typ1% x1´ in my core routines, I thought that the best way would be use it as a pointer, where it at one instance could point to the buffer (for the case with point to point communication in MPI), or pointing to a shared memory address (in that case a pointer is required). 

I will try to see if I can make up an example without being a too lenghty one, but not sure I will succed or how long it will take. But would the latter info provide any better insight on my reasoning of the choices I made. 

 

 

0 Kudos
Reply