It is clear to my what pass by value and pass by reference mean, but what happens in the opposite direction ?
e.g:
subroutine get_flux(flux,ngrid,u,a,c)
implicit none
double precision, dimension(1:ngrid), intent(in) :: u
double precision, intent(in) :: a,c
integer, intent(in) :: ngrid
double precision, intent(out) :: flux
flux = a*u*(1-u)**c
end subroutine
if i call this subroutine by
double precision, dimension(1:ngrid) :: flux
double precision, parameter :: a = 1, c = 5
double precision, dimension(1:ngrid) :: u(:) = 2
call get_flux(flux,ngrid,u,a,c)
Does the subroutine passes a reference back, or a copy of the array ?
I'm not aware of any programming language which, when passing an argument in one direction by reference does not pass the same argument by reference in the other. Certainly in Fortran arguments appear to be passed by reference in both directions. I write appear to be because the standard does not require that arguments be passed by reference, just that the program behaves as if they are. In general that is, sometimes compilers will make copies, perhaps if an array section is passed.
Related
I read on many posts on Stack Overflow that an allocatable array is deallocated when it is passed in a subroutine where the dummy argument is intent(out).
If I consider the following code :
program main
real, dimension(:), allocatable :: myArray
integer :: L=8
allocate(myArray(1:L))
call initArray(myArray)
print *, myArray
contains
subroutine initArray(myArray)
real, dimension(:), intent(out) :: myArray
myArray(:) = 10.0
end subroutine initArray
end program main
the output is right. So, when deallocation occurs, memory is released but the array shape is kept. Is it exact ? Any detailed explanation would be appreciated.
I read different posts on the subject (Can I use allocatable array as an intent(out) matrix in Fortran?, What is the effect of passing an allocatable variable into a subroutine with non-allocatable argument?, ...). So I understand that the array is deallocated but I would like to understand what does it mean because in my code, the size is kept and I am also surprised that this code works.
You are slightly misunderstanding what happens here.
Arrays which are deallocated on entry to a procedure with intent(out) are those allocatable arrays which correspond to an allocatable dummy.
What intent(out) means for an argument depends entirely on the characteristics of the dummy not actual argument.
Allocatable actual arguments which correspond to ordinary dummy arguments are not deallocated. (If they were, the dummy argument which is not allocatable would have to be not allocated!)
Instead, the allocation status of the actual argument remains unchanged and the shape of the assumed (not deferred) shape dummy argument remains the same.
The dummy argument becomes undefined, as an intent(out). For the ordinary dummy argument here, that refers simply to its value (which is immediately defined in that assignment statement).
The deallocation happens when the dummy argument is allocatable and intent(out). Try
real, dimension(:), intent(out), allocatable :: myArray
to achieve that.
The fact that the actual argument in the main program is allocatable is immaterial to a subroutine without an allocatable dummy argument (such as yours).
I strongly suggest to name the array in the main program and the argument in the subroutine differently to better see the difference.
program main
real, dimension(:), allocatable :: mainArray
integer :: L=8
allocate(mainArray(1:L))
call initArray(mainArray)
print *, mainArray
contains
subroutine initArray(argArray)
real, dimension(:), intent(out) :: argArray
argArray(:) = 10.0
end subroutine initArray
end program main
Now, mainArray is the actual argument, argArray is the dummy argument. The dummy argument must be allocatable for deallocation to happen.
This is a follow up to a post that I found on SO: Difference between intent(out) and intent(inout)
The linked question asked about the difference between intent(out) and intent(inout) in Fortran by asking an invalid program.
Could anyone come up with a simple valid program(s) that give different results by changing intent(inout) to intent(out) or vice versa?
Here you go...
program intent_test
implicit none
integer, allocatable :: a(:)
a = [1,2,3,4,5]
call intent_inout (a)
call intent_out (a)
contains
subroutine intent_inout (a)
integer, allocatable, intent(inout) :: a(:)
if (allocated(a)) then
print *, a
else
print *, "Unallocated"
end if
end subroutine intent_inout
subroutine intent_out (a)
integer, allocatable, intent(out) :: a(:)
if (allocated(a)) then
print *, a
else
print *, "Unallocated"
end if
end subroutine intent_out
end program intent_test
1 2 3 4 5
Unallocated
As Steve Lionel's answer, and the comments in my original answer which perhaps sparked this interest, the effects of intent(out) on the initial state of the dummy argument (and the actual argument) are a way in to answering this question.
intent(inout) has the dummy argument reflect the value of the actual argument on entry to the procedure. intent(out) "resets" the dummy argument. In the case of the linked question, this "undefinition" is the cause of the invalid nature of the program.
More precisely, we can say the following things about intent(out) dummy arguments:
allocatable actual arguments become deallocated;
the pointer association of pointer actual arguments becomes undefined;
for a non-pointer dummy argument any component not default initialized becomes undefined.
The linked question fell foul of the third point by trying to reference such an newly undefined value. However, default initialized components are not undefined, leading us to our first class of valid programs:
implicit none
type t
integer :: x=1
end type t
type(t) :: x=t(0)
call s1(x)
call s2(x)
contains
subroutine s1(x)
type(t), intent(inout) :: x
print*, x%x
end subroutine s1
subroutine s2(x)
type(t), intent(out) :: x
print*, x%x
end subroutine s2
end
Crucially, the default initialization of the component means that x%x isn't undefined even on entry to s2, but it takes a potentially different value from the actual argument's component prior to procedure entry.
Coming up with a suitable program with pointer arguments is tricky: a pointer with undefined pointer association status can't be referenced/queried before its pointer association status is redefined.
Which leaves us looking at allocatable components. Unlike with the pointers, where we can't query pointer association status when that's undefined, we can ask about the allocation status. An actual argument corresponding to an intent(out) dummy is deallocated; with intent(inout) the allocation status is unchanged:
implicit none
integer, allocatable :: i
allocate (i)
call s1(i); print*, allocated(i)
call s2(i); print*, allocated(i)
contains
subroutine s1(i)
integer, allocatable, intent(inout) :: i
end subroutine s1
subroutine s2(i)
integer, allocatable, intent(out) :: i
end subroutine s2
end
(This is a simpler version of Steve Lionel's example.)
This all shows that it's possible to have differences. Using intent incorrectly can lead to invalid programs or to significant changes in meaning. Understanding what intent(in), intent(inout), intent(out) and no specified intent mean is a crucial part of being a Fortran programmer.
In my code I have an elemental subroutine which is basically like this:
elemental subroutine calc_stuff (x, a, b, c)
real, intent(in) :: a, b, c
real, intent(out) :: x
x = a/b + c
end subroutine calc_stuff
which I changed to this:
elemental subroutine calc_stuff (x, a, t)
real, intent(in) :: a
type(mytype), intent(in) :: t
real, intent(out) :: x
x = a/t%b + t%c
end subroutine calc_stuff
where mytype is a type containing some scalar real and integer, as well as a real, allocatable array. The members b and c are reals, making the second version basically the same as the first one.
The second version compiles fine on various compilers (Cray, Intel, NEC, GFortran), but now I read that the standard states for elemental subroutines:
All dummy arguments must be scalar, and must not have the ALLOCATABLE or POINTER attribute.
Is my code therefore not standard-conforming when passing a user-defined type to an elemental subroutine, but all the compilers "know" what I want because I am only using scalars from the type and not the allocatable array? Or am I misunderstanding the wording of the standard and everything is fine with the second version?
The dummy argument t is scalar1 and does not have the pointer attribute and does not have the allocatable attribute. It does not violate the condition.
The attributes of components of the type do not have a bearing on the attributes of the type itself.
1 Being of derived type doesn't make an object necessarily non-scalar. Even with multiple, or array components, the object itself may still be scalar. A derived type array is an array with element(s) of that type. Think also of a character object like character(len=3) name: it is scalar but consists of multiple substrings.
I have a Fortran derived type T that contains data arrays of (many) different ranks and types. These arrays are hidden inside a complicated data structure and I would like to have a getter function of that does the following:
a => T%get(data_id)
where "a" is an array pointer of given type, and data_id is an integer that is used to find the data inside the data structure. I do that by overloading many "get_thistype()" functions under a generic name.
TYPE T
PROCEDURE :: get_real
PROCEDURE :: get_integer
GENERIC :: get => get_real,get_integer
END TYPE
This works if the get_thistype() routines are subroutines, but not if they are written as functions. This means my code looks like:
CALL T%get(a,data_id)
which I find much less readable. Is there a way to overload functions that have the same argument list but different return types? or do I have to use subroutines for that?
When a (pointer) assignment statement gets executed in fortran, the right hand side always gets evaluated fully before the assignment takes place. This happens independently of the left hand side, so there is absolutely no way that the LHS can influence the outcome of the evaluation of the RHS. It's just the way the language is designed.
I just came across this post, so for the benefit of anyone see this in the future:
If I understand the question correctly, you can accomplish this by overloading the assignment operator. Example:
file X.f90:
MODULE XModule
TYPE :: X
INTEGER, DIMENSION(:), POINTER :: IntArray
REAL, DIMENSION(:), POINTER :: RealArray
END TYPE
INTERFACE ASSIGNMENT (=)
MODULE PROCEDURE PointToInt
MODULE PROCEDURE PointToReal
END INTERFACE
CONTAINS
SUBROUTINE PointToInt(Ip, V)
INTEGER, POINTER, DIMENSION(:), INTENT(OUT) :: Ip
TYPE(X), INTENT(IN) :: V
Ip => V%IntArray
END SUBROUTINE PointToInt
SUBROUTINE PointToReal(Rp, V)
REAL, POINTER, DIMENSION(:), INTENT(OUT) :: Rp
TYPE(X), INTENT(IN) :: V
Rp => V%RealArray
END SUBROUTINE PointToReal
END MODULE
test driver file Driver.f90:
PROGRAM Driver
USE XModule
TYPE(X) :: Var
INTEGER, DIMENSION(:), POINTER :: I
REAL, DIMENSION(:), POINTER :: R
ALLOCATE(Var%IntArray(2))
ALLOCATE(Var%RealArray(3))
Var%IntArray = [1, 2]
Var%RealArray = [1., 2., 3.]
I = Var
PRINT*, I
R = Var
PRINT*, R
END PROGRAM
Output:
1 2
1.000000 2.000000 3.000000
Hope this helps.
In a calling function I have this:
call ESMF_TimeGet( date, yy=year, mm=month, dd=day, s=sec, rc=rc)
The signature for ESMF_TimeSet is:
! ESMF_TimeGet - Get value in user-specified units
subroutine ESMF_TimeGet(time, YY, YRl, MM, DD, D, Dl, H, M, S, Sl, MS, &
US, NS, d_, h_, m_, s_, ms_, us_, ns_, Sn, Sd, &
dayOfYear, dayOfYear_r8, dayOfYear_intvl, &
timeString, rc)
type(ESMF_Time), intent(in) :: time
integer, intent(out), optional :: YY
integer(ESMF_KIND_I8), intent(out), optional :: YRl
integer, intent(out), optional :: MM
integer, intent(out), optional :: DD
integer, intent(out), optional :: D
integer(ESMF_KIND_I8), intent(out), optional :: Dl
integer, intent(out), optional :: H
integer, intent(out), optional :: M
integer, intent(out), optional :: S
integer(ESMF_KIND_I8), intent(out), optional :: Sl
integer, intent(out), optional :: MS
integer, intent(out), optional :: US
integer, intent(out), optional :: NS
double precision, intent(out), optional :: d_
double precision, intent(out), optional :: h_
double precision, intent(out), optional :: m_
double precision, intent(out), optional :: s_
double precision, intent(out), optional :: ms_
double precision, intent(out), optional :: us_
double precision, intent(out), optional :: ns_
integer, intent(out), optional :: Sn
integer, intent(out), optional :: Sd
integer, intent(out), optional :: dayOfYear
real(ESMF_KIND_R8), intent(out), optional :: dayOfYear_r8
character (len=*), intent(out), optional :: timeString
type(ESMF_TimeInterval), intent(out), optional :: dayOfYear_intvl
integer, intent(out), optional :: rc
type(ESMF_TimeInterval) :: day_step
integer :: ierr
When I'm calling ESMF_TimeSet how is the subroutine able to convert the yy=yr argument into a yy variable inside the subroutine (and similarly for mm and dd)? Also, does FORTRAN care about case-sensitivity of variables?
how is the subroutine able to convert the "yy=yr" argument into a yy variable inside the subroutine?
There is no yy variable in your procedure. Only yy dummy argument. When you call this procedure you use so-called named arguments. This feature is not specific to Fortran. But what's your problem with optional arguments?
And the same for mm and dd. Does FORTRAN care about case-sensitivity of variables?
Fortran is case-insensitive language. So no, it doesn't care.
Okay. I'll try to explain some basics because I have some difficulties with understanding your comments. :)
When it comes to procedures the Fortran terminology differs from the "common" one in some respects:
It's common to distinguish between procedures (performs some tasks returning several results through arguments) and functions (invokes within expression and return a single value which is used in expression) while collectively calling them subroutines. In Fortran we have subroutines and functions collectively calling procedures.
While calling procedure you pass some info through arguments. Commonly entities appeared at procedure definition are called formal arguments and entities appeared in procedure call are called actual arguments. In Fortran formal arguments are called dummy arguments. Be aware, because often dummy arguments are referred to as meaningless arguments which are used only to conform the API, i.e. EmptyParam in Delphi.
When procedure is called (is referenced in terms of Fortran standard)
the actual argument list identies the correspondence between the
actual arguments and the dummy arguments of the procedure.
So basically the correspondence is by position. Some languages (including Fortran) also have the ability to establish correspondence by keyword. The long story short:
The keywords are the dummy argument names and there must be no further
positional arguments after the first keyword argument.
(c) Michael Metcalf, John Reid, Malcolm Cohen. Modern Fortran Explained.
For details see Fortran Standard (you can grab the copy the final draft of the Fortran 2008 standard by the link provided here), 12.5.2 Actual arguments, dummy arguments, and argument association.
So keyword arguments is a feature known as named arguments or named parameters in other languages.
But this feature is not the only one which can help programmer to write concise and readable code for calling procedures without overloading. Some languages also have default arguments. Fortran has similar feature: so-called optional arguments. It looks a bit different but the aim is the same.
Keyword arguments are often used in conjunction with optional arguments. For example, you should use keyword arguments when you leave out optional arguments in the middle of the argument list.
So what's your question is?