Community
cancel
Showing results for 
Search instead for 
Did you mean: 
machalot
Novice
605 Views

Fortran rename on derived type member not allowed?

Jump to solution

I get a syntax error when a use-association rename targets a specific member of a derived type variable, as opposed to the entire derived type variable.

For example, this works:

 

use legacy_interface, x => global_data

 

But this gives a syntax error:

 

use legacy_interface, x => global_data%x

 

The error is: 

 

error #5802: Syntax error: found '%' when expecting one of: , <END-OF-STATEMENT> ;

 

This seems to indicate renaming specific members of a derived type is not allowed.  Is that true?

Are there good workarounds?

I'm using Intel Fortran 19.0.5.281 for Linux.

0 Kudos
1 Solution
Steve_Lionel
Black Belt Retired Employee
576 Views

Correct - you can rename only module-level entities, not subcomponents.

View solution in original post

10 Replies
andrew_4619
Honored Contributor I
588 Views

bring in the whole derived type and then have an associate construct to make a local name for the sub-element

machalot
Novice
555 Views

I'm trying to reuse legacy code that relied on common blocks to share data.  I was hoping to remove all the common blocks, then populate data from a C struct into a Fortran derived type in a module, then rename each member of the derived type variable to the original variable name from the common block.  That way I would not have to change code in the executable lines of the legacy code, but only at the top. 

I think to use an associate construct to do this, the entire legacy subroutine would need to be enclosed within the associate construct, is that right?

FortranFan
Honored Contributor II
543 Views

 

 wrote:

I'm trying to reuse legacy code that relied on common blocks to share data.  I was hoping to remove all the common blocks, then populate data from a C struct into a Fortran derived type in a module, then rename each member of the derived type variable to the original variable name from the common block.  That way I would not have to change code in the executable lines of the legacy code, but only at the top. 

I think to use an associate construct to do this, the entire legacy subroutine would need to be enclosed within the associate construct, is that right?

 

 

Yes, you would need to enclose the code within the construct.

You may really want to think through this and decide what how you want to proceed with your legacy code: "let sleeping dogs lie" is always an option, or you can refactor your code in any number of ways to something modern.

There are several options (online search will help) including the dreaded one of resorting to POINTERs if the much safer alternative of ASSOCIATE with a similar concept is unworkable for you.  Here's an example:

 

module m
   type :: t
      integer :: n = 0
      real :: x = 0.0
   end type
   type(t), target, save :: foo = t() !<-- Derived type instance 'simulated' as save'd module variable
   integer, pointer, save :: n => foo%n !<-- POINTER to one component
   real, pointer, save :: x => foo%x    !<-- POINTER to another component
contains
   subroutine output()
      print *, "In m::output:"
      print *, "foo%n = ", foo%n
      print *, "foo%x = ", foo%x
   end subroutine
end module
module legacy_code_m
   use m, only : n, x  !<-- Note this USE statement
contains
   subroutine legacy_sub()
      n = 42
      x = 99.0
   end subroutine
end module
program p
   use legacy_code_m, only : legacy_sub
   use m, only : output
   call legacy_sub()
   call output()
end program

 

 

Read through the whole snippet if you're keen on using such an approach involving POINTER.  Upon execution of this simple case, you should get:

 

 In m::output:
 foo%n =           42
 foo%x =    99.0000000

 

andrew_4619
Honored Contributor I
520 Views

well you could also just replace the common with a module with the same entities in it as the common. So long as your code does not do any of the old style "sharing" of the common space type hacks.  That is a very minimal code change.

machalot
Novice
514 Views

What you describe is exactly what we did with another code base a few years back -- a direct swap of commons for modules with all the same variable names.  Worked beyond our wildest dreams.

However, in this case the motivation for using a derived type is to take advantage the C binding features to pass data to and from a C structure in the calling function.  I suppose one approach is to create a setter routine that copies all the members into separate variables.  I was just hoping to avoid that.

andrew_4619
Honored Contributor I
508 Views

You have several ways available, I guess the detail of what you do depends on the amount of work needed and what you want to do in the future. For what it's worth the associate idea looks like:

 

    subroutine example
        use mymodule, only: myType
        implicit none (external)
        !real :: x,y,z
        !common /mytype / x,y,z
        associate ( x => mytype%x, &
                    y => mytype%y, &
                    z => mytype%z     )
                    ...
                    ...
        end associate
    end subroutine example

 

machalot
Novice
485 Views

Thanks @andrew_4619, that makes it very clear.  Looks like applying associate constructs to avoid changing the operational code would be relatively light weight.

Steve_Lionel
Black Belt Retired Employee
577 Views

Correct - you can rename only module-level entities, not subcomponents.

View solution in original post

machalot
Novice
559 Views

Thank you Doctor. 

Is there an underlying technical reason this should not be possible as a future language feature?

Steve_Lionel
Black Belt Retired Employee
554 Views

You're really not asking for a rename, which would be something like renaming global_data%x to global_data%y. If you want x to stand in for global_data%x, then @andrew_4619 has exactly the right solution - use ASSOCIATE. That's what it's for and it's already in the language.

Reply