Post by Nasser M. AbbasiIt seems to me the correct solution to this is to do like
In c++ one can write foo::z, and in Ada foo.z, same in Java
foo.z, etc... where foo in the package or module name.
This problem has been solved long time ago. Just pre-append
the package/module name to the variable, using special character.
I agree that this was a choice made in the language a long time ago.
This choice was made in the mid 1980's and standardized in f90. I
have not used ada, so maybe that predates the fortran design, but
other languages like perl and java, which do address this problem in
different ways, came after fortran, not before. In a previous post
I mentioned Mathematica, in which the scope of variables also causes
numerous problems in large programs; that also came before fortran.
I agree that there are advantages and disadvantages of the various
approaches. I happen to like the way fortran did it because it
scales to large programs better than the other choices without
unnecessary complications. The largest perl program in existence is
quite small by fortran standards, so the tradeoffs between namespace
pollution and simplicity are different.
In fortran, if you want to keep track of where variables come from,
then make it a point to use the ONLY clause in your USE statements.
I think in many cases that is a good idea, but in other situations
it is unnecessarily verbose.
If you need to rename variables or subprograms in order to avoid
conflicts, then you can do that. If not, then you can keep things
simple.
Also, if you use fortran modules written by other people, you do not
need to know the details of how those modules are implemented to use
the information in them, you only need the API to that module. If
you import someone else's module A, which has some variable Z, then
you can just reference Z in the normal way (or you can rename it
locally, as you choose). You do not need to know that in the
implementation of that module, the variable was actually declared in
module D, which was used by module C, which was then used by module
B, which was then used by module A. In other languages, you would
need to know all of that in your code and reference the variable as
A.B.C.D.Z (or something analogous). Then if module A were
subsequently rewritten and rearranged and Z was moved around, all of
your user code that referenced A.B.C.D.Z would need to be changed to
A.NEWB.NEWC.NEWD.NEWE.NEWF.Z or whatever. And the same problem
would apply to every other variable in that module that you accessed
in your code. For large programs written and maintained by a large
number of programmers, that is a nice feature of the fortran
implementation. It allows "what is written is Vegas to stay in
Vegas" without coming back and causing problems later.
On the other hand, if you want variables like that to have their
ancestry exposed, then in module D you can define the variable to be
D_Z. Then in module C you can rename it to C_D_Z, and in module B
you can rename it to B_C_D_Z, and finally in A you can rename it to
A_B_C_D_Z. That way you get what you seem to think is a good idea,
but it is not imposed on you, you have the choice to implement it
this way or not.
Now after saying all that, there are some odd things that can happen
with nested modules. For example, you sometimes think that you are
renaming a variable in one module when actually you are renaming a
variable in another module. This is because the fortran compiler
knows where all those module variables are really defined, and when
you rename it in a USE statement, it covers that same variable in
all modules which are USEd. So I think that compilers should have
an option to print out that information somehow to make it easier to
track down these situations.
Here is a little example that demonstrates this:
module B
integer :: Z=10
end module B
module A
use B
end module A
program scope
use A, W=>Z
use B ! you think you are accessing Z here.
implicit none
write(*,*) 'W=', W
write(*,*) 'Z=', Z
end program scope
This program will not compile because the variable Z in module B has
been redefined. If the variable Z in module A came from somewhere
else, then it would compile and you would have access to both
variables. So if you did not know how modules A and B were
implemented, but only had knowledge of the API for them, you might
be puzzled why your program does not compile. This is where I think
the compiler should be able to print out a list of all the variables
and where they are declared so that you can understand what is the
problem.
If you remove the implicit none statement in the above, then the
program does compile, but the Z that you think you are printing is
an undeclared local variable, not the Z that is in module B. So the
programmer has shot himself in the foot twice, and this is perhaps
even harder to figure out. If the compiler could just print out the
information that it knows, then this would be pretty quick to debug,
but otherwise it is a problem. Of course, I recommend using
implicit none for this and other reasons, but it shows the problems
that can arise with nested modules.
Here is a version of the above program that renames everything
according to the nested modules:
module B
integer :: B_Z=10
end module B
module A
use B, A_B_Z=>B_Z
end module A
program scope
use A
use B
implicit none
write(*,*) 'A_B_Z=', A_B_Z
write(*,*) 'B_Z=', B_Z
end program scope
This program does compile and you have access to the variable in two
different ways in the main program. If you change what might appear
to be one variable, then the other one changes too. Of course, the
compiler knows this, this is not a hidden alias, but you the
programmer might not. So again, it would be good if the compiler
could print out this kind of information.
$.02 -Ron Shepard