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

Not getting access to variables using MODULE

TommyCee
Beginner
1,394 Views
Consider this simple F90 program construct:

Module MyStuff
implicit none
{Declarations: character vars.
integer vars.
real arrays x, y, z}

Contains
subroutine Curley(a,b)
integer intent(in) :: a,b
do 100
{some computations using a & b and real arrays x/y/z}
100 enddo
end subroutine Curley

subroutine Larry(x,y)
integer intent(in) :: a,b
do 200
{some computations using a & b and real arrays x/y/z}
200 enddo
end subroutine Larry

subroutine Moe(x,y)
integer intent(in) :: a,b
do 300
{some computations using a & b and real arrays x/y/z}
300 enddo
end subroutine Moe

end Module MyStuff

program MAIN
use MyStuff
implicit none

Call Curley()
Call Larry()
Call Moe()

end program MAIN

++++++++++++
I hope I have sufficiently described the premise. I am most interested in making the declaration details at the top of the Module accessible to ALL parts of the program, including the ("contained") subroutines.

The program compiles flawlessly. At run time, all parts of MAIN have access to all variables (as expected). However, when control gets to sub. Curley, integers a & b are known (but of course they would be; they're explicitly defined). But these are the only two appearing in the Locals (debug) window!

All the other variables in declaration section (top of the Module) are not known and can't be traced. They appear in a separate group (Watch1) to the right in the debug window w/ values of "Undefined variable ..."

I'm a little new to 'MODULE' but I thought the whole idea was to allow global access to variables, as did the COMMON block in F77. I wonder what I'm missing here; this shouldn't be a tall order.

Any ideas?



0 Kudos
13 Replies
mecej4
Honored Contributor III
1,394 Views
INTENT cannot be specified for any variables other than those that are subprogram arguments. Therefore, the program sketch that you listed above cannot be correct (subroutines LARRY and MOE), and a complete program with such statements would produce syntax errors.

Please edit your post accordingly.
0 Kudos
TommyCee
Beginner
1,394 Views
As I have presented my sketch, INTENT is applied to integers a & b which are subprogram arguments (for subs. Curley, Larry & Moe, resp. contained in the Module). Therefore, mecej4's comment is confusing.
0 Kudos
TommyCee
Beginner
1,394 Views
OK, I now think I know what mecej4 meant and am re-sketching my code (I made a typo):

Module MyStuff
implicit none
{Declarations: character vars.
integer vars.
real arrays x, y, z}

Contains
subroutine Curley(a,b)
integer intent(in) :: a,b
do 100
{some computations using a & b and real arrays x/y/z}
100 enddo
end subroutine Curley

subroutine Larry(a,b)
integer intent(in) :: a,b
do 200
{some computations using a & b and real arrays x/y/z}
200 enddo
end subroutine Larry

subroutine Moe(a,b)
integer intent(in) :: a,b
do 300
{some computations using a & b and real arrays x/y/z}
300 enddo
end subroutine Moe

end Module MyStuff

program MAIN
use MyStuff

Now hopefully we can resove the problem.
implicit none

Call Curley()
Call Larry()
Call Moe()

end program MAIN


Now we can hopefully resolve the problem.
0 Kudos
Steven_L_Intel1
Employee
1,394 Views
Do I understand correctly that you're asking about the behavior of the debugger, and not your program?
0 Kudos
John4
Valued Contributor I
1,394 Views

"Undefined" is the initial state of a variable, until you assign some value to it. Maybe you're confusing "undefined" with "undeclared". The debugger is just showing you that you haven't assigned anything to those variables (and maybe that those variables are not being used at all in the program unit you're debugging.

Although the debugger, with default settings, tends to initialize variables to zero, you shouldn't rely on that behavior.

In order to prevent your variables from becoming undefined when they run out of scope, try putting a "save" statment in the module, somewhere between the "implicit none" and the "contains".

0 Kudos
abhimodak
New Contributor I
1,394 Views
Hi TommyCee

May be the following will help:-

[1] In the test program below (in [4]), I have put breakpoint at line # 9.

(a) When this breakpoint is hit, in the "Locals" window of the debugger I see: A = 1.0, B = 1.0, N = 4223422, and M = 0. Values of A and B are as expected. N is actually uninitialized/undefined and the value there is "garbage". {As a side-note, usage of variable n before assigning a value can be trapped using run-time switch /check:uninit.}

(b) I do not see variable "J" in the Locals. I believe this is expected behavior of the debugger.

(c) In a watch window, if I type J then I will get "Undefined Variable J". If I type OM::J then I see it as zero. {However, this value of 0 is a fluke. The variable is actually uninitialized. See the following post, if interested: http://software.intel.com/en-us/forums/showthread.php?t=78105&o=a&s=lr}

(d) Uncomment statement J = 1 from subroutine Method and rebuild. Now when the breakpoint at line # 9 is hit, J will appear in the locals window. In a watch window, you can see J either by typing J or OM::J. However, when you step-out to line # 22, J will be greyed out in the watch window but OM::J will still correctly show its value as 1. At this breakpoint, if you again type J in the watch window, you will again get "Undefined Variable J".

(e) Thus, the correct way of seeing module variables in the debugger is to use ModuleName :: VariableName syntax.

[2]
(a) As Steve pointed out, this is the behavior of the debugger and not the language.

(b) As per the rules of the langauge, the module variable J is available to all the prorgram units that use it, for example the main program. It is also to the procedures contained in the module through host-association. {These are perhaps not a rigirous statements but good enough way to describe, I think.}

[3] I think --
(a) What mecej4 was trying to tell you was that you have used "intent(in) :: a, b" in the interfaces of subroutines Larry and Moe. However, you have written Subroutine Larry(x,y) instead of Larry(a,b).

(b) {What makes thing complicated is that you have put x and y in the module variable declarations.} However, I think (3a) is all that mecej4 was correctly pointing out.

(c) Just to pick one more, I might as well add that there is a missing comma between integer and intent... I am sure you were just trying to put a sample and that's valid point. However, please always try to put an actual program rather than some abstraction. Also use the syntax highlighting tool in this editor, if possible.

[4] Finally below is the sample. After such a long response, I hope it helps. I am using IVF 11.1.065 on WinXP with VS2005.

Abhi


----

[fortran]      Module OM
         Implicit None
         Integer :: J
      Contains
         Subroutine Method(a,b)
            Real, Intent(IN) :: a, b
            Integer :: m, n
            m = 0
            Print *, a, b
            !J = 1
         End Subroutine Method
      End Module OM
      
      Program Test_ModInit
         Use OM
         Implicit None
         Real :: a, b
         Integer :: k
         a = 1.0
         b = 1.0
         Call Method(a,b)
         Print *, "back in the main program."
      End Program Test_ModInit[/fortran]



0 Kudos
TommyCee
Beginner
1,394 Views
Thanks for replies by Steve, John & Abhi.
Steve: I guess my question goes equally to the program (structure) and to the debugger - hand in hand.
John: I think you may be missing my overarching question but, to your suggestion of inserting a Save statement, I did that a few days ago to no avail. I must say I researched Modules as much as possible before posting my question and found no examples like the one I posted (in which the top of the Module had extensive declarations that one expected access to by contained subroutines). I saw something about Save and tried it; didn't have the intended effect.
Abhi: I appreciate you extensive comments and exemplar code which I studied). Jumping to you[3](a) & (b), I thought I indicated that I realized this and that's why I re-posted my code structure. And as for your (c), you're right - I did omit a necessary comma. I was trying to get the gist of the problem (big picture) before you. You make a good point about posting actual code (vs. an abstraction) but I think the latter should suffice for this purpose. Also, you suggested to "use the syntax highlighting tool in this editor". Good idea: I just now browsed "How to attach a file..." and was reminded about the pencil icon. It's been a while ...

Your code is somewhat similar to mine, though I wish you had declared many more variables of different flavors (including arrays) at the top of Module OM; you included only integer J. I will tell you this:

Your comment: "the correct way of seeing module variables in the debugger is to use ModuleName :: VariableName syntax." was huge. I tried that for the "Undefined variables" listed in the Wach1 window and, indeed, their contents are revealed. This, however seem to be a huge inconvenience and I never had to do this before. I want them to show up automatically in the Locals window!

With all this in mind, I'll here repost my code, making all the corrections that have been pointed out. (Then I'll post a revision that will best make my point - see below.)

[bash]Module MyStuff
implicit none
{Declarations:  character vars.
                       integer vars.
                       real arrays x, y, z}

Contains
subroutine Curley(a,b)
integer, intent(in) :: a,b
do 100
  {some computations using a & b and real arrays x/y/z}
100  enddo
end subroutine Curley

subroutine Larry(x,y)
integer, intent(in) :: a,b
do 200
  {some computations using a & b and real arrays x/y/z}
200  enddo
end subroutine Larry

subroutine Moe(x,y)
integer, intent(in) :: a,b
do 300
  {some computations using a & b and real arrays x/y/z}
300  enddo
end subroutine Moe

end Module MyStuff

program MAIN
use MyStuff
implicit none

Call Curley()
Call Larry()
Call Moe()

end program MAIN[/bash]

Now I'll revise the code above using a sledge hammer method which makes the problem I reported go away:
[bash]Module MyStuff
implicit none
{Declarations:  character vars.
                       integer vars.
                       real arrays x, y, z}

Contains
subroutine Curley(a,b)
integer, intent(in) :: a,b
{Declarations:  character vars.
                       integer vars.
                       real arrays x, y, z}
do 100
  {some computations using a & b and real arrays x/y/z}
100  enddo
end subroutine Curley

subroutine Larry(x,y)
integer, intent(in) :: a,b
{Declarations:  character vars.
                       integer vars.
                       real arrays x, y, z}
do 200
  {some computations using a & b and real arrays x/y/z}
200  enddo
end subroutine Larry

subroutine Moe(x,y)
integer, intent(in) :: a,b
{Declarations:  character vars.
                       integer vars.
                       real arrays x, y, z}
do 300
  {some computations using a & b and real arrays x/y/z}
300  enddo
end subroutine Moe

end Module MyStuff

program MAIN
use MyStuff
implicit none

Call Curley()
Call Larry()
Call Moe()

end program MAIN[/bash]

At run time, the code above offers no surprises: ALL variables are automatically displayed in the Locals window, as desired. Beautifully. All the cards are on the table. So what's the deal here? Reproducing the variable declarations in different code blocks is something I've known I could do all along. Of course one can do that. If one likes redundancy, once can always recopy code pieces over and over again. This is what I think many have somehow missed in my question.

I come back to where I started:

The purpose of COMMON blocks (in F77) was to obviate redundant rewriting of variable declarations so all program units could have access. I thought the whole idea w/ MODULEs was to allow global access to variables, as did the COMMON block in F77. NB: As I explained at the outset, MAIN has (and always did have) access to variables declared in Module (via Use). That was never the issue. The problem was Module's contained subunits; they're "blind" w/o repeading the declaration that is at the heart of Module (as I demonstrated).

Now that I've re-cast my question w/ better explanation, can anyone please tell me how to really exploit MODULE in the context of my program (which is not at all uncommon) so that the declarations don't have to be repeated and so that the Locals window can display and track variables of interest. Sorry ths is so long but that is the question (which I hope is more clear by now).



0 Kudos
John4
Valued Contributor I
1,394 Views

You should always put a SAVE statement in the module anyway (I tend to put mine right after the IMPLICIT NONE statement).

The debugger only shows the module variables in the Locals window, if they're being used somehow in the contained procedure. That said, you can certainly trick the debugger with a block that, although never gets executed, contains a list of the "missing" variables, e.g.:

[fortran]module mod1
    implicit none
save
integer :: a = 5, b = 6, c = 7 contains subroutine f() integer :: d if (.FALSE.) print *, a, b, c d = 8 print *, 'd = ', d end subroutine end module mod1 program prog1 use mod1 call f() end program prog1 [/fortran]
Or, if it still seems to troublesome for you, just get used to the :: syntax like everybody else.

0 Kudos
abhimodak
New Contributor I
1,394 Views
[1] May be I have missed a something big here but when you "declare the variables that were declared as module variables "locally" in the subroutine", those variables are the local variables and NOT the module variables.

For example, in my test program,
(a1) change line # 7 to Integer :: m, n, J, (a2) keep line # 10 uncommented, (a3) put breakpoints at line 9 and 22. I will call these BP1 and BP2, respectively.

(b) The change (a1) makes variable J "local" to subroutine method and it is NOT the module variable J.

(c) To see this put OM::J and J in the watch window.

(d) When BP1 is hit, the variable OM::J will remain 0 while the local variable J will be assigned value 1 at line # 10. {J will appear in the "Local" window regardless of whether line # 10 is commented or not.}

(e) This variable local variable J "evaporates" after exiting subroutine Method. {In fact, have line 10 assigning J commented out and put a breakpoint at the end subroutine statement at line # 11. You will see that at BP1, variable J will have some "garbage" value. It will change to 0 at the end statement since local J is gone and module variable J's value is displayed.

(f) Thus, in your revised version the declarations at line 10, 20, and 30 make arrays x, y, z "local" to subroutine Curley, Larry, and Moe. To reiterate, suppose that inside Curley x is set to 1. When you enter procedure Larry through call at line 45, x is NOT 1. It will be uninitialized since it is local.

[2] Thus, you will have to get used to putting module variables in the watch window and not seeing them in locals, at least with IVF that's the case. OR as John's example showed, you can trick the compiler to see the module variables by putting some statement.

[3] By language, the module variables ARE available in the "contained" procedures through "host-association".

[4] Perhaps I am pushing it too much but I will once again note that with "implicit none" defined at 2 and with no implicit defined inside the subroutines: (a) at line 18,19 and 28,29 you will get a compile-time error since a and b are not in the interface. (b) Since you have put (x,y) in the interface, you will HAVE to declare x and y as those will be treated as local variables (dummy arguments in this case). (c) Compile-time errors for line 44, 45, and 46 are also obvious.

I apologize if I have stressed points too much.

Abhi
0 Kudos
TommyCee
Beginner
1,394 Views
OK, my final thoughts:

Firstly, thanks for additional comments by John & Abhi.

John, I'll make a note of your SAVE suggestion. I tried it in my case and it didn't seem to have the effect I was hoping for. You're probably on the right track. Also, your suggestion to:

'trick the debugger with a block that, although never gets executed, contains a list of the "missing" variables'

was a little lost on me; you didn't reference exactly which lines effected this in your sample code.

Abhi, I appreciate your sample code, too, and I think I get the gist of what you are saying. In thinking this over, and better understanding the parameters & constraints here, I think to some degree I may have forgotten what we mean by Locals variable tracking. As such, I may have had unrealistic expectations of the CVF compiler window in displaying what I had hoped to see (and track). Several in this thread have - in their own ways - helped to clarify that. The Locals window is context oriented (my inelegant term): it displays what it understands to be the "local" variables in the program unit where control is at that time. Once control leaves that unit, another set of variables becomes "local". I think I get that variables that aren't "local" can be tracked in one of the Watch windows. I'm afraid I had lost sight of that concept, and it really has nothing to do with whether one uses a Module structure for declaring variables or not in terms of their "access" for tracking. I got my program working fine now so it's cool ...



0 Kudos
John4
Valued Contributor I
1,394 Views

The SAVE suggestion is just to avoid module variables to become undefined under certain situations (the Fortran 2008 standard will correct that mistake; until then, make sure to put a SAVE statement in every module).

The line that tricks the debugger is #8 (in my previous post), which sort of self-explanatory (since I mentioned that it never gets executed):

[fortran]if (.FALSE.) print *, a, b, c[/fortran]
The IF will get executed while you're on the debug configuration, but not the PRINT statement ---and the optimization should remove that line in the release configuration.

As i said before, the debugger will show module variables in the Locals window if you use them somehow in the contained procedure you're debugging. Even though the PRINT statement is never executed, the debugger will display the variables listed on it.

0 Kudos
TommyCee
Beginner
1,394 Views
Thanks John. That helps a lot.

if(.FALSE.) ...
looks a littel strange to me. If what's false? Wouldn't you have top use some logical variable in this statement?

I'll have to meditate on this trickery of which you uspeak (maybe experiment w/ your code when I can). This is fairly novel (2me) - I'll have to cogitate on it. But is sounds like something that may help me down the road.

TC
0 Kudos
mecej4
Honored Contributor III
1,394 Views
This may be strange to you, but it is quite straightforward if you read it while consulting a Fortran manual/book.

To elaborate, note that

IF ()

and

IF () THEN

END IF

are standard statements and constructs in Fortran. The item is required to be an expression of type LOGICAL. Expressions may be built from constants, variables, function references and operators.

In the code that John suggested to you, has been supplied in the simplest form of a logical expression, namely, a LOGICAL constant, the constant .FALSE. Thus, the value of is immediately available, without the compiler having to evaluate any expression. One may compare the situation with the following analog for, say, real variables:

Compare

y = 2.5

with

a=1.0
b=1.5
x = atan(1.0)*2
y = a*sin(x) + b

Similar code may be seen in C, as well. For example:

#if 0
...
#endif

and

if(0){
...
}
0 Kudos
Reply