Enlico
Enlico

Reputation: 28384

Structure of a fortran program with modules and subroutines

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

Answers (1)

Mathieu Coquerelle
Mathieu Coquerelle

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

Related Questions