# Fortran: variables in the list of arguments for Subroutines

Hi all,

Suppose I declare X in the main program.

Then in the following subroutine:

Call example(list of arguments)

------------------------------------
subroutine example(list of arguments)

x=y+z

end subroutine
-------------------------------------

I have two options:
(a) including X in the list of argument, then I have to declare X within the subroutine.
(b) not including X in the list of argument, then I do not have to declare X within the subroutine.

I don't know the advantages of one over the other.

Which method should I use?

Thanks,

Lam

DrClaude
Mentor
(b) not including X in the list of argument, then I do not have to declare X within the subroutine.
Assuming that you want to know the result of x=y+z in the main program, that won't work. In that case, the x in the main program is not the same variable as in the subroutine.

phinds
Gold Member
2021 Award
You need to study "pass by reference" and "pass by value". I don't know the FORTRAN conventions for those (or even if it allows both, though I assume it must).

DrClaude
Mentor
You need to study "pass by reference" and "pass by value". I don't know the FORTRAN conventions for those (or even if it allows both, though I assume it must).
Fortran is strictly pass by reference.

Assuming that you want to know the result of x=y+z in the main program, that won't work. In that case, the x in the main program is not the same variable as in the subroutine.

Here is my test:

=======================
program test
use examp
implicit none

y=1.
z=2.

call calx

print*,'x=',x

end

======================
module examp

implicit none
real x,y,z
contains

subroutine calx

x=y+z

end subroutine

end

=======================

And I got x =3 out in the main program.

Lam

DrClaude
Mentor
Ah, you are using a module. The problem with that approach is that you lose in flexibility. What if you wanted to add w and z instead?

In some cases, where the number of arguments would be too big, passing variables through a module is worth it. But it can make programs more difficult to read and debug. I would suggest avoiding it when possible and passing arguments instead.

Ah, you are using a module. The problem with that approach is that you lose in flexibility. What if you wanted to add w and z instead?

Can you elaborate on this?

In some cases, where the number of arguments would be too big, passing variables through a module is worth it. But it can make programs more difficult to read and debug. I would suggest avoiding it when possible and passing arguments instead.

Yes, I have quite a lot of arguments for different subroutines. What I did was, I put all the needed arguments in the brackets. Now I want to test, without putting arguments in the brackets would I have the same results, same performance, etc.

Thanks,

Lam

DrClaude
Mentor
Can you elaborate on this?

Code:
program test

real :: w,x,y,z

x = 1.0
y = 3.0

! later in the program

w = 10.1 ! (but still y = 1.0)

end program test

real, intent(in) :: a,b
real, intent(out) :: c

c = a+b

end subroutine adder

To give another example, imagine you want to create a subroutine to perform a Gaussian quadrature (integration) on regularly spaced data. You can write
Code:
subroutine gauss(n,f,dx,gauss_quad)

integer, intent(in) :: n
real, dimension(n), intent(in) :: f
real, intent(in) :: dx

gauss_quad = (0.5 * (f(1) + f(n)) + sum(f(2:n-1))) * dx

return
end subroutine gauss_quad
which is very flexible: you can reuse to same function in many programs, or in the same program where sometimes you integrate along x (with certain values nx and dx), and sometimes along y (with different values ny and dy).

The disadvantage is if the values of n and dx never change, and you call gauss_quad from within other subroutines, you always have to pass dx to that intermediate subroutine, even if it doesn't need that value:
Code:
subroutine do_something(n,a,b,c,d,f,dx)
...
...
end subroutine do_something
In that case, it might be best not to carry the dx everywhere and use something like
need that value:
Code:
module gauss_quad_mod
integer :: n
real :: dx

program test
...
n = 1024
dx = (x2-x1)/(n-1)
...
call do_something(n,a,b,c,d,f)
...
end program test

subroutine do_something(n,a,b,c,d,f)
...
...
end subroutine do_something

real, dimension(n), intent(in) :: f

gauss_quad = (0.5 * (f(1) + f(n)) + sum(f(2:n-1))) * dx

return
end subroutine gauss_quad

Thanks DrClaude,

In my case I have a program structured like this:

===============================

do n=1,100000000

call sub1(list_of_arg_1)

call sub2(list_of_arg_2)

...........

end do

============================

List 1 is used for Sub1, list2 is used for sub2, etc. This is the main theme in my program.

I just have few steps using different lists of arguments for the same subroutine, something like in your example:

call thesamesub(list_of_arg_1)

call thesamesub(list_of_arg_2)

So I wonder, for those many subroutines which always use the same lists of arguments, if I omit the list of arguments would I gain speed in running my program?

Thanks,

Lam

DrClaude
Mentor
So I wonder, for those many subroutines which always use the same lists of arguments, if I omit the list of arguments would I gain speed in running my program?
Most probably not. As I posted earlier, all variables are passed by reference, which means that there is no overhead with copying values in memory. Compiler optimization (in particular inlining) will take care of eliminating most other performance costs in such a situtation, as far as I know.

Thanks,

If so, I should have explicit lists of arguments then. Actually, I don't have to change anything to my program, it's already been that way .

Lam

Mark44
Mentor
Code:
program test

real :: w,x,y,z

x = 1.0
y = 3.0

! later in the program

w = 10.1 ! (but still y = 1.0)

end program test

real, intent(in) :: a,b
real, intent(out) :: c

c = a+b

end subroutine adder

For the simple example above I would have written the adder routine as a function. The code would look something like this:
Code:
program test

real :: w, x, y, z, sum

x = 1.0
y = 3.0

z = sum(x, y)

! later in the program

w = 10.1 ! (but still y = 1.0)

z = sum(x, w)
end program test

function sum(a, b)

real, intent(in) :: a, b

return a + b

end function adder
Caveat: This code probably compiles and runs correctly, but I haven't had a Fortran compiler for a number of years, so haven't tested it.

SteamKing
Staff Emeritus
Homework Helper
It used to be that, if you had a program with subroutines which required the use of a large number of variables, instead of passing the variables to the subroutine using argument lists, you would create static data areas using a COMMON statement or statements and include the COMMON statements in the subroutine. This worked especially well when large programs had to be overlaid due to small computer memories.

AlephZero