Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Fortran passing parameters with brackets prevents changes

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                                                              
like image 362
v.tralala Avatar asked Nov 20 '16 03:11

v.tralala


2 Answers

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)
like image 110
IanH Avatar answered Oct 11 '22 13:10

IanH


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.

like image 37
High Performance Mark Avatar answered Oct 11 '22 15:10

High Performance Mark