Reputation: 28384
This is part of a main program
PROGRAM program1
USE method
USE variables
IMPLICIT NONE
:
CALL method_init(A,a1end,C)
:
END PROGRAM program1
The call to method_init
, contained in the module method
, "initializes" a method in that it builds arrays a1end
and C
form the array A
(other calls to other procedures contained in the module should follow).
Arrays a1end
and C
are part of the method, so they are both declared in the method
module; the array A
is not part of the method (it could be "solved" with another method), so it is declared in the module variables
.
The arrays C
and a1end
could be used by subroutines not contained in the method
module, so they must be declared before the CONTAINS
statement.
So, the subroutine contained in the method
module could use these variables without using them as input/output variables, but this would make unclear the role of the subroutine (the call would be simply CALL method_init
, so "How does this subroutine operate? Which arrays does it use? And which modify? ..."), so I prefer to have the call as CALL method_init(A,a1end,C)
.
This means that the module method
is like this
MODULE method
IMPLICIT NONE
REAL, DIMENSION(:,:), ALLOCATABLE :: C ! declared here to be used...
REAL, DIMENSION(:,:), ALLOCATABLE :: a1end ! ...by procedures outside this module
:
CONTAINS
SUBROUTINE method_init(A,a1end,C)
IMPLICIT NONE
REAL, DIMENSION(:,:), ALLOCATABLE, INTENT(IN) :: A ! deferred shape (it's allocated elsewhere in the main program)j
REAL, DIMENSION(:,:), ALLOCATABLE, INTENT(OUT) :: C ! declared here to be used...
REAL, DIMENSION(:,:), ALLOCATABLE, INTENT(OUT) :: a1end ! ...as input/output variables
:
ALLOCATE(C( ),a1end( ))
:
END SUBROUTINE method_init
END MODULE method
I'd like to know if this is a correct way of programming. Is it just a matter of taste?
EDIT The question, in short, is: Is a correct way of programming to use variables defined in a module as input/output arguments of procedure contained in the module itself? Or it is better to write subroutines with no arguments? Or everything is just a matter of taste?
The questions/answers linked by @Vladimir F make me think that yes, it' a matter of taste. Nevertheless none of these question touches the specific point I'm interested into (i.e. procedures that are in a module and use a variable defined in the module as input/output arguments).
Upvotes: 0
Views: 776
Reputation: 91
My answer would be that you did the right choice as I would always recommend to write procedures with all its parameters and avoid using global variables (like C
and a1end
in your example).
However, many people in Fortran use to use global variables and would not bother passing these arguments, sometimes for wrong reason (like "it's faster to write").
But it is still totally correct to use global variable in a module if you imagine the latter as being a box containing its own specific and unique set of parameters. Maybe then you would want to specify them as Fortran parameter
(with the associated keyword).
When you question yourself about passing arguments or using global variables for a function/subroutine, a simple choice would be whether or not your function is bound to be called/reused with other different parameters somewhere else in your code, or sometime later in your development process.
This is particularly true when you think of your module as a box that you can unplug and give to a mate for his own needs, then you might want your method_init
to be more flexible, thus expliciting the arguments.
Note: in your example, I would recommend to name your subroutine arguments differently than your module's variables in order to avoid any confusion in the code and be able to use them without any conflict:
MODULE method
IMPLICIT NONE
REAL, DIMENSION(:,:), ALLOCATABLE :: C
REAL, DIMENSION(:,:), ALLOCATABLE :: a1end
CONTAINS
SUBROUTINE method_init(A,my_a1end,my_C)
IMPLICIT NONE ! Already specified above
REAL, DIMENSION(:,:), ALLOCATABLE, INTENT(IN) :: A
REAL, DIMENSION(:,:), ALLOCATABLE, INTENT(OUT) :: my_C
REAL, DIMENSION(:,:), ALLOCATABLE, INTENT(OUT) :: my_a1end
ALLOCATE(my_C( ),my_a1end( ))
! Here you can work with module's C and a1end
! Given that they have been effectively allocated
! You can also test whether C and my_C are the same object or not (pointerwise speaking)
END SUBROUTINE method_init
END MODULE method
Upvotes: 2