I am using a module within a module and expected to get a compilation conflict error for variable IB in the sample shown below, but did not. I looked in the forum and the problem seems similar to this recent post, but is not quite the same: https://community.intel.com/t5/Intel-Fortran-Compiler/Scope-of-USE-statement-in-an-INTERFACE-block/t...
If IB is declared in subroutine DYN_IN, program compiles but IB declared within INPUT_DATA seems to be ignored (IB within main program remains 0). If IB is not declared in DYN_IN, program functions as expected and IB becomes 1 in the main program. Is this a bug or am I making an error? Thank you!
PROGRAM MODTEST USE INPUT_DATA USE DYNAMICS_DATA IMPLICIT NONE IB = 0 CALL DYN_IN STOP END MODULE INPUT_DATA INTEGER(4) IB END MODULE INPUT_DATA MODULE DYNAMICS_DATA IMPLICIT NONE INTERFACE MODULE SUBROUTINE DYN_IN END SUBROUTINE DYN_IN END INTERFACE END MODULE DYNAMICS_DATA SUBMODULE (DYNAMICS_DATA) DYNAMICS_SUBMOD USE INPUT_DATA IMPLICIT NONE CONTAINS MODULE SUBROUTINE DYN_IN IMPLICIT NONE INTEGER(4) IB ! should this be an error due to conflict with INPUT_DATA? IB = 1 END SUBROUTINE DYN_IN END SUBMODULE DYNAMICS_SUBMOD
I would expect that IB within DYN_IN would be a local variable and that you would have no access to IB in the module.
Local variables with the same name as a global entity take precedence.
Please consider the following line of thought.
Suppose there was no declaration of the variable IB in DYN_IN. Would the variable still be available in the module subroutine because of host association or use association? IB is available by use association in the submodule that contains DYN_IN. Inside the contained subroutine DYN_IN, however, it is available by association from the immediate host, i.e., the submodule.
Local variable declarations override variables of the same name that are host-associated. Local variable declarations come into conflict with variables of the same name that are use-associated.
It would be instructive to move USE INPUT_DATA from the submodule into DYN_IN and try compiling the modified code. The compiler may alert you to the conflict between use-associated variables and the local variable.
Things may become more complicated if, instead of simple variables as in this example, we have some variables that have the pointer attribute.
Thank you for the great explanation. I had started in the habit of sometimes placing the USE statement one time in the specification portion of module above the CONTAINS statement rather than repeating it multiple times in perhaps several dozen subroutines below. I can see that doing this can cause possible unexpected adverse behavior without error or warning in the compile. By moving the USE statement within the subroutine I did get the error that I was looking for, so I will proceed in that fashion.
@Bill1 wrote: .. I had started in the habit of sometimes placing the USE statement one time in the specification portion of module above the CONTAINS statement rather than repeating it multiple times in perhaps several dozen subroutines below. I can see that doing this can cause possible unexpected adverse behavior without error or warning in the compile. By moving the USE statement within the subroutine I did get the error that I was looking for, so I will proceed in that fashion.
What you've decided as per quoted comment above can prove rather onerous and limiting with library code, especially as the code tries to achieve more complex tasks.
I suggest you look into ", ONLY : " clause with your USE statements (look at only-list in the link below):
And also study the IMPORT facility introduced starting with Fortran 2018 and the ONLY clause with it also:
The above combination can provide you with better control of associated entities (whether via use-association or host-association) and reduce "namespace pollution" and "collisions" as referred to in programming parlance.
Here's a variant of your code for a hypothetical scenario to show these options:
MODULE INPUT_DATA INTEGER(4) IB real :: x END MODULE INPUT_DATA MODULE DYNAMICS_DATA IMPLICIT NONE INTERFACE MODULE SUBROUTINE DYN_IN END SUBROUTINE DYN_IN END INTERFACE END MODULE DYNAMICS_DATA SUBMODULE (DYNAMICS_DATA) DYNAMICS_SUBMOD USE INPUT_DATA, only : x !<-- say, access is needed only to x in this submodule IMPLICIT NONE CONTAINS MODULE SUBROUTINE DYN_IN IMPORT, NONE !<-- say "DYN_IN" is a simple routine and no access to module entities are needed INTEGER(4) IB IB = 1 END SUBROUTINE DYN_IN ! Additional procedures which consume 'x' from INPUT_DATA may be contained below END SUBMODULE DYNAMICS_SUBMOD PROGRAM MODTEST USE INPUT_DATA USE DYNAMICS_DATA IMPLICIT NONE IB = 0 CALL DYN_IN print *, "IB = ", IB, "; expected is 0" STOP END
Thanks for the suggestion. I have been using ONLY, but usually only in situations where I am adding a USE to an existing subroutine and I know specifically why I have added the USE and usually only when there are a few items to list. I figure that this helps document the code as well, indicating the reason why the USE was included. I will look at the IMPORT as well.
Thanks for all of your insightful help through the years. I have been reading your articles since the CVF days. If Intel is open to user suggestions, I would suggest that the capability for issuing a compiler warning when this host-association conflict occurs would be very helpful, as this can cause erroneous results and be very difficult to track down. When adding MODULES and IMPLICIT NONE into a 70,000 line legacy code application, it is very easy to trip up on this!
I have advocated in the past for "usage" warnings in cases where the usage is standard-conforming but might not be what the programmer expects. The case you cite would have to be something the user asked for explicitly, rather than default, as even informational diagnostics for standard code result in complaints to support.
There is no "conflict" here - declaring a local variable that overrides a host-associated variable is something commonly done and is in the language for a good reason. I'd have a hard time justifying any sort of diagnostic for this.
@Bill1 then adding a USE to an existing code my motto is "only use USE with ONLY" this avoids possible confusions and give clear indication of what the programmer intended and what the routine might modify