Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.

Question about defined assignment

johnyb_
New Contributor I
380 Views

in the following example, should the program not behave the same way,whether I assign a variable to itself enclosed or not in parentheses ?

module m_test

    type t_1
        integer :: i,j,k
        contains
            procedure, private :: t_1_ass_t_1
            generic :: assignment(=)    => t_1_ass_t_1
    end type
  contains
    subroutine t_1_ass_t_1(var, expr)
        class(t_1), intent(out) :: var
        class(t_1), intent(in)  :: expr
        var%i = 0
        var%j = 0
        var%k = 0
        if (expr%i > 0) then
            var%i = expr%i
            var%j = expr%j
            var%k = expr%k
        endif
    end subroutine
end module
program test
    use m_test
    
    type(t_1) :: x,y
    
    x = t_1(1,2,3)
    x = x
    print *, x
    y = t_1(1,2,3)
    y = (y)
    print *, y
end program

However the output is:

C:\TEMP>ifort test.f90
Intel(R) Visual Fortran Intel(R) 64 Compiler for applications running on Intel(R) 64, Version 16.0.0.110 Build 20150815
Copyright (C) 1985-2015 Intel Corporation.  All rights reserved.

Microsoft (R) Incremental Linker Version 11.00.61030.0
Copyright (C) Microsoft Corporation.  All rights reserved.

-out:test.exe
-subsystem:console
test.obj

C:\TEMP>test
           0           0           0
           1           2           3

C:\TEMP>

In clause 12.4.3.4.3 the Fortran 2008 standard says "A defined assignment is treated as a reference to the subroutine, with the left-hand side as the first argument and the right-hand side enclosed in parentheses as the second argument."

 

Johny

0 Kudos
7 Replies
mecej4
Honored Contributor III
380 Views

At first, I wondered if the statement x = x, which results in the call t_1_ass_t_1(x, x), is in violation of the rules that prohibit subroutine arguments being aliased. When you do x = (x), the call is made with (x, copy_of_x) as the arguments, so there is no aliasing.

However, reading your post again, I see that the quote of the standard already states that the second argument is to be considered as being the R.H.S. expression in parentheses, so there should be no aliasing question.

0 Kudos
Steven_L_Intel1
Employee
380 Views

You're right that it should work the way you expect. We had this problem for a long time but I thought we had fixed it a couple of releases ago. Your example clearly demonstrates we have more work to do - I will send this on to the developers. Thanks for the nice example. Issue ID is DPD200381046.

0 Kudos
netphilou31
New Contributor II
380 Views

Hi,

I am not sure to understand, but when assigning x to x on line 29, does this not do the same as calling t_1_ass_t_1(x,x) where the first lines are nullifying the values of var (=x) and then because expr%i (i.e. x%i) is equal to zero leave var (=x) equal to zero ? For me that's the only explanation I can find but I am not sure about what the standard says or what the compiler should do. However my main question is: what does y = (y) means on line 32? (mainly in that case what is the purpose of the parenthesis?) and why does this not produce the same results as for x = x?

Best regards,

Phil.

0 Kudos
mecej4
Honored Contributor III
380 Views

Surrounding an argument with parentheses causes evaluation of the expression within the parentheses, if needed, copying the result to an anonymous temporary variable, and passing the anonymous copy to the subroutine. When a variable is passed this way, the called routine can alter the copy, but the original is protected since the called subroutine does not even know about its existence. Try this test code:

program pararg
implicit none
integer :: x(3) = [1,7,3]
call sub(x,(x))
write(*,*)x
end program pararg

subroutine sub(x,y)
integer x(3),y(3)
x(1:3)=0
where(y > 1)x = y
return
end subroutine sub

 

0 Kudos
netphilou31
New Contributor II
380 Views

mecej4 wrote:

Surrounding an argument with parentheses causes evaluation of the expression within the parentheses, if needed, copying the result to an anonymous temporary variable, and passing the anonymous copy to the subroutine. When a variable is passed this way, the called routine can alter the copy, but the original is protected since the called subroutine does not even know about its existence. Try this test code:

program pararg
implicit none
integer :: x(3) = [1,7,3]
call sub(x,(x))
write(*,*)x
end program pararg

subroutine sub(x,y)
integer x(3),y(3)
x(1:3)=0
where(y > 1)x = y
return
end subroutine sub

 

 

Thanks a lot for the explanation. I did not think that could behave differently with and without the parentheses

Best regards,

0 Kudos
mecej4
Honored Contributor III
380 Views

It is one of those language features that is not frequently used and, when you first see it, may appear rather quixotic.

0 Kudos
jimdempseyatthecove
Honored Contributor III
380 Views

This should be a caution to someone writing a formatting program to tabulate, indent, and otherwise cleanup source code to not remove seemingly unnecessary parenthesis.

Jim Dempsey

0 Kudos
Reply