Fortran: variables in the list of arguments for Subroutines

  • #1

Main Question or Discussion Point

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
 

Answers and Replies

  • #2
DrClaude
Mentor
7,148
3,281
(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.
 
  • #3
phinds
Science Advisor
Insights Author
Gold Member
2019 Award
15,907
5,585
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).
 
  • #4
DrClaude
Mentor
7,148
3,281
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.
 
  • #5
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
 
  • #6
DrClaude
Mentor
7,148
3,281
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.
 
  • #7
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
 
  • #8
DrClaude
Mentor
7,148
3,281
Can you elaborate on this?
Code:
program test

real :: w,x,y,z

x = 1.0
y = 3.0

call adder(x,y,z)

! later in the program

w = 10.1 ! (but still y = 1.0)

call adder(x,w,z)

end program test


subroutine adder(a,b,c)

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
real, intent(out) :: gauss_quad

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)
...
call gauss_quad(n,a,dx,int_a)
call gauss_quad(n,f,dx,int_f)
...
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
end module gauss_quad_mod


program test
use gauss_quad_mod
...
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)
...
call gauss_quad(a,int_a)
call gauss_quad(f,int_f)
...
end subroutine do_something


subroutine gauss(f,gauss_quad)
use gauss_quad_mod

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

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

return
end subroutine gauss_quad
 
  • #9
Thanks DrClaude,

I see your point.

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
 
  • #10
DrClaude
Mentor
7,148
3,281
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.
 
  • #11
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
 
  • #12
33,265
4,965
Code:
program test

real :: w,x,y,z

x = 1.0
y = 3.0

call adder(x,y,z)

! later in the program

w = 10.1 ! (but still y = 1.0)

call adder(x,w,z)

end program test


subroutine adder(a,b,c)

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)
  [STRIKE]call adder(x,y,z)[/STRIKE]

  ! later in the program

  w = 10.1 ! (but still y = 1.0)

  z = sum(x, w)
  [STRIKE]call adder(x,w,z)[/STRIKE]
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.
 
  • #13
SteamKing
Staff Emeritus
Science Advisor
Homework Helper
12,798
1,666
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.
 
  • #14
AlephZero
Science Advisor
Homework Helper
6,994
291
Your option (b) of putting making "all" your variables accessible everywhere is a very bad idea. The main problem is that one day you will forget you were already using a variable named something like X, and use it again for something else. Your code will compile and run, but it won't give the right answers!

If you are just starting to learn programming, get into the good habit of only using variables that are "local" to each subroutine, and passing all the information that a subroutine needs through the parameter list.

Eventually, (e.g. when you are working on programs that are 100,000 lines long rather than 100 lines) you might find some good reasons to declare variables inside a module (for example, to make them available to all the subroutines in the module, but to hide them from everything outside of it). But using language options like that "just because you can" is usually a bad idea.
 
  • #15
Thank you guys for all your advice!

Lam
 

Related Threads on Fortran: variables in the list of arguments for Subroutines

Replies
10
Views
6K
Replies
6
Views
2K
Replies
4
Views
9K
  • Last Post
Replies
3
Views
2K
Replies
6
Views
4K
  • Last Post
Replies
3
Views
5K
Replies
2
Views
2K
Replies
3
Views
598
Top