Scope of "use module" and associated linking error [duplicate] - linker

My intended use is
program main
use mod
external sub
call sub
end program main
subroutine sub
! code here calls subroutines in mod
end subroutine sub
Specifically, will module mod be in scope in subroutine sub? Also, I'd be interested to know more generally when a module is in/out of scope. I'm using gfortran 4.6.1, if it matters.

It is not in scope of subroutine sub, as sub cannot call routines or use variables from mod, because sub is not part of the program main. They have nothing in common, are separate compilation units and only may call each other (if they are callable).
Consider this:
program main
external sub
call sub
end program main
subroutine sub
use mod
! code here calls subroutines in mod
end subroutine sub
Here, you can use variables and routines from mod in sub, because sub explicitly uses mod.
Another example, where sub is an internal procedure of main:
program main
use mod
call sub
contains
subroutine sub
! code here calls subroutines in mod
end subroutine sub
end program main
Also in this case you can use things from mod in sub because everything from main is in scope in sub.
Finally, in this case mod is not in scope, it is similar to the original case.
program main
use mod
use mod2
call sub
end program main
module mod2
contains
subroutine sub
! code here calls subroutines in mod
end subroutine sub
end module mod2
Another issue is the undefining of module variables, when they go out of scope. Fortran 2008 solved this by making all module variables implicitly save.

Related

Declaration of dummy argument explicit shape arrays in Fortran

I thought that the specification of an explicit shape dummy argument array in a subroutine can involve any integer variables, including other dummy variables (usual cases), module variables, and local variables of the present subroutine. But it turns out that local variables (which are not dummy variables) can not be used in the specification.
An example is as follows:
module mp
implicit none
contains
subroutine p(b)
integer :: m=4, n=4 !not integer,parameter :: m=4, n=4
integer :: b(m,n)
end subroutine p
end module mp
gfortran will raise Error: Variable 'm' cannot appear in the expression at (1)
For this example, I can use integer,parameter :: m=4, n=4 to avoid this, but I do not understand why the original case does not work, considering the fact that the bounds/extents of explicit shape arrays do not need to be known at compile time. A modified version of the above example works:
module mp
implicit none
integer :: m=4, n=4
contains
subroutine p(b)
integer :: b(m,n)
end subroutine p
end module mp
Considering the slight difference between the two examples, I expect both of them work, but in fact the former does not. Could someone explain the reason?
Update: I found out that this is a very subtle issue because it depends on whether the subroutine is contained in a module or is standalone, it also depends on the version of gfortran. I have posted examples in the answer region.
Formally, there are requirements on what the bounds in such an explicit shape array are. These don't simply map to "don't have to be known at compile time".
For an array explicit shape, the array bounds must be specification expressions. Often, such bounds must be constant expressions, but this is not the case for dummy arguments. This partly gives rise to the (erroneous) thought that they needn't be known at compile time.
However, the constraints for a specification expression must still be met. These can be found in Fortran 2018 10.1.11. In particular, a local variable (even a saved one) may not appear in a specification expression.
For the examples of the question, using named constants such as with
integer, parameter :: m=4, n=4
is allowed in a specification expression. Indeed, the specification expressions m and n are even constant expressions in this case.
If we had
function p(b,m,n)
integer m, n, b(m,n)
end function
then we have valid specification expressions for the array bounds, even though m and n are not constants.
The right workaround is to put the procedure body in a BLOCK construct:
module mp3
contains
subroutine p(b)
implicit none
integer :: m=4, n=4
BLOCK
integer :: b(m,n)
END BLOCK
end subroutine p
end module mp3
The fact that it works in gfortran-8 as a standalone subroutine should be reported on bugzilla. You've got a nice minimal example there.
EDIT: I hadn't noticed that b was a dummy argument. I was thinking more in terms of something like
module mp3
contains
subroutine p(x)
implicit none
real x
integer :: m=4, n=4
BLOCK
integer :: b(m,n)
END BLOCK
end subroutine p
end module mp3
But as the example stands the BLOCK approach just can't work. Also gfortran 8.1.0 rejects the form with the standalone subroutine:
subroutine p(x)
implicit none
real x
integer :: m=4, n=4
integer :: b(m,n)
end subroutine p
Error: Variable 'm' cannot appear in the expression at (1)
(As it should)
Finally, I found out that this is a very subtle issue because it depends on the version of gfortran and also depends on whether the subroutine is contained in a module or is standalone.
Neither gfortran-4.8 or gfortran-8 can compile successfully the following code:
module mp3
contains
subroutine p(b)
implicit none
integer :: m=4, n=4
integer :: b(m,n)
end subroutine p
end module mp3
But if we consider a standalone subroutine as follows:
subroutine p(b)
implicit none
integer :: m=4, n=4
integer :: b(m,n)
end subroutine p
Then gfortran-4.8 still reject this form, but gfortran-8 accepts this, which may be just a bug in gfortran-8 because further testing (by user5713492) indicates that gfortran-8.1.0 also rejects this form.
In summary, local variables of a subroutine are not allowed in the specification expression of dummy argument arrays.
Using local non-constant variables in specification expressions is not very often needed. So it is not a terrible idea to forbid this usage.

Fortran array mismatch in subroutine but no error?

I have a program that seems to work properly,
but I don't understand how it can,
because there seems to be an obvious error.
Main program(which use 'implicit') calls a subroutine:
implicit integer(i-n)
implicit double precision(a-h,o-y)
implicit complex*16(z)
call do_coulomb(zvecs0,zdualvecs0,n_f,n_f,1,
$ nsubfilling,zcorrmatrix,0,aldet01abs,
$ zcoulomb,epsilon)
where arrays, 'zvecs0','zdualvecs0','zcorrmatrix' are declared,
but there is no declaration of 'nsubfilling' anywhere.
(It could be a mistake or remnant of old version.)
Since I could not find
any declaration of array 'nsubfilling' in main program
('grep -i nsubfilling *' ),
I suppose 'nsubfilling' will be treated as an integer variable.
This is a subroutine of question:
subroutine do_coulomb(zvecs,zdualvecs,n_A,n_Ap,n_C,
$ nsubfilling,zcorrmatrix,n1_p0,aldet01abs,
$ zcoulomb,eps)
implicit integer(i-n)
implicit double precision(a-h,o-y)
implicit complex*16(z)
include "input.inc"
dimension zvecs(0:L-1,0:L-1,0:L-1,0:Lt,0:1,0:1,0:n_f-1)
dimension zdualvecs(0:L-1,0:L-1,0:L-1,0:Lt,0:1,0:1,0:n_f-1)
dimension nsubfilling(0:n_Ap-1,0:n_C-1)
dimension zcorrmatrix(0:n_Ap-1,0:n_Ap-1)
('L' 'Lt' are defined in the "input.inc" file.)
Because 'nsubfilling' is defined as an array in the subroutine,
I thought the mismatch between main and subroutine would cause an error.
However, the program seems to run okay even with mismatch.
I tried to print out some variables.('n_f'=4,'n_c'=1 in this run)
This is the output:
Before 1st call in main:
nsubfilling= 1
zcorrmatrix(0,0)= (20.510951695209510,0.13579118691198364)
zcorrmatrix(0,1)= (-1.0490102491588316,0.59453967445518319)
zcorrmatrix(1,0)= (-1.3791781667351797,-0.26247624491732802)
zcorrmatrix(n_f-1,n_f-1)= (20.510951695209513,-0.13579118691198364)
Inside do_coulomb subroutine:
nsubfilling= 1 0 1 1
zcorrmatrix(0,0)= (20.510951695209510,0.13579118691198364)
zcorrmatrix(0,1)= (-1.0490102491588316,0.59453967445518319)
zcorrmatrix(1,0)= (-1.3791781667351797,-0.26247624491732802)
zcorrmatrix(n_f-1,n_f-1)= (20.510951695209513,-0.13579118691198364)
n1p0= 0
After 1st call in main:
nsubfilling= 1
zcorrmatrix(0,0)= (20.510951695209510,0.13579118691198364)
zcorrmatrix(0,1)= (-1.0490102491588316,0.59453967445518319)
zcorrmatrix(1,0)= (-1.3791781667351797,-0.26247624491732802)
zcorrmatrix(n_f-1,n_f-1)= (20.510951695209513,-0.13579118691198364)
The output shows that 'nsubfilling' is treated as an integer in main routine,
but considered as an array in the subroutine and also
the subroutine recognizes 'zcorrmatrix' correctly
even with mismatch.
But, how this can be possible? I think there should be an error.
Could you let me understand how it work?
Thank you.
The main program does not have an explicit interface to subroutine do_coulomb. This means that the main program cannot check at compilation time whether the ranks of the actual arguments in the main program match the ranks of the dummy arguments in the subroutine.
An explicit interface can be provided in a number of ways:
having subroutine do_coulomb as an internal subprogram of the main program (subroutine after main subprogram, after a CONTAINS statement and before the END statement of the main program), this is called host association;
via an interface block in the main program (provide name of subroutine, list of dummy arguments, their types and attributes); or
by including the subroutine inside of a module (foo) and adding a use statement (use module foo) before the implicit declarations, this is called use association.
Why is your program not crashing? Well, because subroutine do_coulomb thinks it has access to a chunk of memory corresponding to nsubfilling of the size specified inside of the subroutine, and it happens to not do anything otherwise illegal when manipulating it - the chunk of memory happens to be in use by the same application. If the declared size of nsubfilling was very very big, and/or you had fewer arrays declared, it is likely that access to nsubfilling led to a segmentation fault.
Note that, even if you have an explicit interface, the ranks and the dimensions may not match - and that can be legal, as long as the total size of the dummy argument in the subroutine is not larger than the total size of the actual argument in the main program.

Where are Lua's "global" local values stored?

I need to call a Lua function from C and as long the function is global I can find it in the global table, but if it is declared local, how can I push the address on the stack to call it?
function MyGlobal()
print("Global")
end
local function MyLocalGlobal()
print("Local")
end
Calling MyGlobal() from C isn't a problem it works fine. I lookup the function in the global table.
But how do I call MyLocalGlobal() from C? It isn't in the global table, but where is it and how can I push the address?
I'm using Lua 5.3.4.
The MyLocalGlobal() function isn't really global. It's local to the anonymous function that represents the whole chunk of loaded code.
What is really happening when you call lua_load/lua_loadstring:
return function(...) -- implicit functionality outside of code to be loaded
-- your file starts here --
function MyGlobal()
print("Global")
end
local function MyLocalGlobal()
print("Local")
end
-- file ends here --
end -- implicit functionality outside of code to be loaded
You can get MyLocalGlobal later either with debugging facilities (by means of 'debug' library), or you should explicitly return required interface at the end of that source file, and grab/read the interface on native side right after you've loaded/executed the chunk.

Using modules in Fortran: Undefined reference to `parse_'

I am trying to use the parse routine described here to parse a string in Fortran90. When following the link in the document one can download a .zip with two f90-files, which I have done. I have then compiled them gfortran -c precmod.f90 && gfortran -c stringmod.f90. I have also added use strings to my program.
Despite of this, I receive the following error when compiling (gfortran stringmod.o precmod.o calcs.o server.o):
calcs.o: In function `calculate_':
calcs.f90:(.text+0x174): undefined reference to `parse_'
collect2: error: ld returned exit status 1
calcs.f90 is shown below and server.o is a server written in C that should be invoked by calcs.
program name
use strings
use iso_c_binding, only: C_CHAR, C_NULL_CHAR, C_INT
implicit none
! type declaration statements
character(255) query
integer calc, ans, portnum, calculate
interface
subroutine server(portnum) bind(C, name="server")
use iso_c_binding, only: c_int
integer(kind=c_int), value :: portnum
end subroutine server
end interface
! executable statements
print *, "Please provide me with a port number. Plz. <3"
read "(1i9)", portnum
call server(portnum)
end program name
function calculate(query)
implicit none
character(255) query, op
integer length, i, calculate
integer, dimension (:,:), allocatable :: inputarray
call parse(query, ' ', inputarray, length)
do i=1,size(inputarray)
print *, inputarray(i, 1)
end do
calculate = 5
end function calculate
I have tried to add public to the top of stringmod.f90.
When we have something like
program
end program
function func()
end function
then the function func is an external function, even when this is given in the same source code file as the main program. This external function knows nothing about the main program, and in turn the main program knows little about the external function.
Part of this lack of knowledge is that, in the example of the question, the fact that the subroutine parse has an explicit interface (through the module) in the main program is irrelevant to calculate.
That is, the function calculate has its own scope and has no host. To gain access to the module procedure parse it can itself use the module strings:
function calculate(query)
use strings, only : parse
implicit none
end function
There is a hint to this lack of being aware that parse is a module procedure in strings. The name decoration in parse_ (that single trailing underscore) is a common way to mangle an external procedure. Module procedures (without bind(c)) generally have much more elaborate symbol names.
Finally, I'll repeat something from the comments. Earlier, I said that the main program knows little about the external function. In the main program we have the declaration
integer ... calculate
which says that the external function calculate (which has an implicit interface) has a return type of integer. The function, in this case, could instead be made an internal function
program
use strings, only : parse
contains
integer function calculate
end function
end program
and not only does the function calculate have an explicit interface (removing also the need for that return declaration in the main program) but it also has access to parse through host association.

How to get VBA Subroutine to call a function that passes an array to another function within the subroutine

I am trying to get my VBA subroutine to run a function that creates an array and then passes that array to another function which further processes those array items. I have made an example that is extremely simple and functions exactly like my actual code. it is as follows:
Sub SubRoutine()
ProcessArray CreateArray
End Sub
Function ProcessArray(Arr() As Variant) As Variant
End Function
Function CreateArray() As Variant
Dim Array1(1 To 4) As Variant
CreateArray = Array1
End Function
It's just the two functions and the subroutine which calls those two functions. The compiler refuses to compile my code and explains to me that:
Compile error:
Type mismatch: array or user-defined type expected
To which I can only say that everything is the same data type and the argument passed is indeed an array. Just in case you were wondering, yes I have tried with an array that has had data allocated to it.
I know it's something subtle I am missing in VBA syntax but I have not seen an example like this. Any insight would be greatly appreciated.
Change this line:
Function ProcessArray(Arr() As Variant) As Variant
to this:
Function ProcessArray(Arr As Variant) As Variant
This way your function will now accept a Variant that contains an array, instead of looking for an array of Variants. As you said, a subtle but significant difference.
I think what still wasn't answered is why
1. MySub(MyArg)
works just fine, but
2. MyOtherSub(MyArg1, MyArg2)
does not
This blog entry explains it well.
Essentially, you can pass an argument which would normally be byref as byval:
Call MySub(Arg1, (Arg2)) 'Arg1 is passed byref, Arg2 is passed byval
Code #1. works because VBA thinks you are passing one argument byVal so it doesnt count as parentheses being used in a Sub call without the Call keyword. As mentioned in other answers, no parentheses are allowed in a Sub call without the Call keyword.
The Call keyword requires Params in parentheses. So with the Call keyword Call MySub(MyArg) would actually pass MyArg byRef because the parentheses are used as the enclosure for arguments.
Code #2 does not work because there is no valid way to justify the parentheses in the syntax (it is only allowed with the Call keyword.

Resources