Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pointers as components of derived types

I understand from this answer (Fortran copy of pointer) that I should try to use allocatable arrays rather than array pointers as components of derived types. I intend to do so but am locked into my current code for the next year and need to be able to use it and understand it until I can make the bigger and better changes next year.

I also think this question is of some general interest because I think fortran behavior here is pretty unintuitive although apparently correct. So there is likely value in better understanding how and why it works (or else I assume the compiler wouldn't let us do this at all, right?).

Sorry for the longish intro. I'll try to do this as one annotated program that has been whittled down as much as possible:

program main

   type tRet
      real :: agi
      real :: wages_tgt(5)          ! compiler won't let me declare as
                                    ! target but later I point to this
      real, pointer :: wages(:)
   end type tRet

   type(tRet), target :: ret             ! I don't quite understand 
   type(tRet), target :: orig1, orig2    ! why but compiler insists
                                         ! these be targets
   ret%wages => ret%wages_tgt(1:1)
   ret%wages = (/ 11. /)
   orig1 = ret
   ret%wages = (/ 99. /)
   orig2 = ret

That's the top half of the program, here's some results with print output shown as comments to the right:

   ! This is not want I want and I was surprised, but it is kind
   ! of explained in the other answer why this happens, so OK...

   print *, "orig1%wages ", orig1%wages    ! 99.
   print *, "orig2%wages ", orig2%wages    ! 99.


   ! But if I copy from orig1 or orig2 into ret then it
   ! works like I wanted it to work in the first place!
   ! But I don't completely understand why it works...

   ret = orig1
   print *, "ret%wages   ", ret%wages      ! 11.
   print *, "orig1%wages ", orig1%wages    ! 11.
   print *, "orig2%wages ", orig2%wages    ! 11.

   ret = orig2
   print *, "ret = orig2 "
   print *, "ret%wages   ", ret%wages      ! 99.
   print *, "orig1%wages ", orig1%wages    ! 99.
   print *, "orig2%wages ", orig2%wages    ! 99.

end program main

I'm happy for any nice explanation of what is going on here. The irony here, I guess, is that I'm not so worried about why this is a bad idea but rather why does my workaround seem to work fine?

Or maybe the easiest way to summarize my question is: What exactly is pointing to what?

Compiler: GNU Fortran (GCC) 4.8.5 20150623 (Red Hat 4.8.5-16)

like image 658
JohnE Avatar asked Feb 15 '26 20:02

JohnE


1 Answers

What is happening here is that when you copy a derived data type, different things happen for each component of the derived type. When you do orig1 = ret:

  • Declared arrays, such as wages_tgt, are assigned new values. This is equivalent to saying orig1%wages_tgt = ret%wages_tgt. Each of these arrays occupy separate places in memory.
  • Pointers, such as wages, are made to point to wherever the source pointer is currently pointing. This is equivalent to saying orig1%wages => ret%wages. The destination of both of these pointers is the same location in memory. In the example here, the only location in memory ever pointed to by any wages is ret%wages_tgt.

With that in mind, your result makes sense to me. Adding some selective additional annotations:

ret%wages => ret%wages_tgt(1:1)

ret%wages = (/ 11. /)   ! so wages_tgt = 11 also

orig1 = ret             ! This is BOTH a copy and re-point
                        ! * orig1%wages_tgt =  ret%wages_tgt (11)
                        ! * orig1%wages     => ret%wages_tgt

ret%wages = (/ 99. /)   ! this changes ret%wages & ret%wages_tgt
                        ! to 99 and also orig1%wages since it is
                        ! also pointing to ret%wages_tgt.

                        ! note that orig1%wages_tgt is UNCHANGED 
                        ! (still 11) but nothing is pointing to it!

Lower down in the code...

ret = orig1  ! ret%wages_tgt = orig1%wages_tgt (11) 
             ! no repointing actually happens this time b/c we have
             ! set up a circular relationship between all the
             ! pointers such that ALL of them point to ret%wages_tgt
like image 114
Ross Avatar answered Feb 21 '26 15:02

Ross