In this question I asked about a method to explicitly prevent passed arguments to change. An obvious solutions is defining copies of the arguments and operate the algorithm on those copies. However in the comment I was pointed to the fact, that I could call the function and wrap the argument I didn't want to change in brackets. This would have the same effect as creating a copy of that passed variables so that it would not change. But I don't understand how it works and what the brackets are actually doing. So could someone explain it to me?
Here is a simple example where the behaviour occurs as I described.
1 program argTest
2 implicit none
3 real :: a, b, c
4
5 interface !optional interface
6 subroutine change(a,b,c)
7 real :: a, b, c
8 end subroutine change
9 end interface
10
11 write(*,*) 'Input a,b,c: '
12 read(*,*) a, b, c
13
14 write(*,*) 'Values at start:'
15 write(*,*)'a:', a
16 write(*,*)'b:', b
17 write(*,*)'c:', c
18
19
20 call change((a),b,c)
21 write(*,*)'Values after calling change with brackets around a:'
22 write(*,*)'a:', a
23 write(*,*)'b:', b
24 write(*,*)'c:', c
25
26
27 call change(a,b,c)
28 write(*,*)'Values after calling change without brackets:'
29 write(*,*)'a:', a
30 write(*,*)'b:', b
31 write(*,*)'c:', c
32
33 end program argTest
34
35
36 subroutine change(a,b,c)
37 real :: a, b, c
38
39 a = a*2
40 b = b*3
41 c = c*4
42
43 end subroutine change
44
45
46
The syntax (a)
, in the context of the code in the question, is an expression. In the absence of pointer results, an expression is evaluated to yield a value. In this case the value of the expression is the same as the value of the variable a
.
While the result of evaluating the expression (a)
, and the variable a
, have the same value, they are not the same thing - the value of a variable is not the same concept as the variable itself. This is used in some situations where the same variable needs to be supplied as both an input argument and as a separate output argument, that would otherwise run afoul of Fortran's restrictions on aliasing of arguments.
HOWEVER - as stated above - in the absence of a pointer result, the result of evaluating an expression is a value, not a variable. You are not permitted to redefine a value. Conceptually, it makes it no sense to say "I am going to change the meaning of the value 2
", or "I am going to change the meaning of the result of evaluating 1 + 1
".
When you use such an expression as an actual argument, it must not be associated with a dummy argument that is redefined inside the procedure.
Inside the subroutine change
, the dummy argument that is associated with the value of the expression (a)
is redefined. This is non-conforming.
Whether a copy is made or not is an implementation detail that you cannot (and must not) count on - the comment in the linked question is inaccurate. For example, a compiler that is aware of this restriction discussed above knows the subroutine change
cannot actually change the first argument in a conforming way, may know that a
is not otherwise visible to change
, and therefore decide that it doesn't need to make a temporary copy of a
for the expression result.
If you need to make a temporary copy of something, then write the statements that make a copy.
real :: tmp_a
...
tmp_a = a
call change(tmp_a, b, c)
I think the explanation is this, though I can't point to a part of the standard that makes it explicit, ...
(a)
is an expression whose result is the same as a
. What gets passed to the subroutine is the result of evaluating that expression. Fortran is disallowing an assignment to that result, just as it would if you passed cos(a)
to the subroutine. I guess that the result of (a)
is almost exactly the same as a copy of a
, which might explain the behaviour that is puzzling OP.
I don't have Fortran on this computer, but if I did I'd try a few more cases where the difference between a
and (a)
might be important, such as
(a) = some_value
to see what the compiler makes of them.
@IanH's comment, below, points out the relevant part of the language standard.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With