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

Final with Overloaded Assignment

Horne__Steven
Beginner
417 Views

I have a program with a derived type that has a final procedure and an assignment operator overload, as shown below:   

    module MyTypeModule
        implicit none
        
        type MyType
            real, allocatable, dimension(:) :: myArray
        contains
            final :: Finalize
        end type MyType
        
        interface assignment(=)
            module procedure :: MyTypeAssign
        end interface
    contains
        
        subroutine Finalize(this)
            type(MyType), intent(inout) :: this
            
            if (allocated(this%myArray)) deallocate(this%myArray)
        end subroutine Finalize
        
        subroutine MyTypeAssign(left,right)
            type(MyType), intent(out) :: left
            type(MyType), intent(in) :: right
            
            if (allocated(right%myArray)) left%myArray = right%myArray
        end subroutine MyTypeAssign
    end module MyTypeModule

    program TestCodeAssignmentFinalize
        use MyTypeModule
        implicit none

        type(MyType) :: a,b
    
        allocate(a%myArray(10))
        a%myArray = 1.0
        write(*,*) "a is allocated? ",allocated(a%myArray)
        write(*,*) "setting a = a"
        a = a
        write(*,*) "a is allocated? ",allocated(a%myArray)
        write(*,*) "b is allocated? ",allocated(b%myArray)
        write(*,*) "setting b = a"
        b = a
        write(*,*) "b is allocated? ",allocated(b%myArray)
    end program TestCodeAssignmentFinalize

The console output is as follows:

 a is allocated?  T
 setting a = a
 a is allocated?  T
 b is allocated?  F
 setting b = a
 b is allocated?  T

 

When I comment out the assignment interface, I get the following console output:

 a is allocated?  T
 setting a = a
 a is allocated?  F
 b is allocated?  F
 setting b = a
 b is allocated?  F

You can see that with intrinsic assignment, the array in a is getting deallocated before being assigned to itself, whereas it remains allocated with the overloaded assignment.  Is this expected behavior?  If it is expected, then is there a way to get around the deallocation when I have a = a and intrinsic assignment?

0 Kudos
5 Replies
Steve_Lionel
Honored Contributor III
417 Views

The deallocation is happening in your final routine - I assume you know that but the wording of your question makes me wonder.

I think your real question is: "Is it correct that intrinsic assignment triggers finalization but defined assignment doesn't?" The answer is yes. Quoting the standard:

9 When an intrinsic assignment statement is executed, the variable is finalized after evaluation of expr and before the definition of the variable.
NOTE 4.49
If finalization is used for storage management, it often needs to be combined with defined assignment.

0 Kudos
IanH
Honored Contributor II
417 Views

I can't check current release, but the results in the original post indicate that the compiler isn't honouring the ordering specified by that standard fragment, when the defined assignment interface block is commented out and intrinsic assignment is in use.  The value that results from evaluating the right hand side of the assignment has an allocated component, so the value of the left hand side after the assignment should similarly have an allocated component.

0 Kudos
Horne__Steven
Beginner
417 Views

Thank you for your replies.  Yes, I understand that the deallocation is happening in my final routine.  I am using Intel Visual Fortran Compiler 17.0.2.187 [IA-32].

We are running into the situation where where have something like array(a)=array(b) and a=b, and array's type has an allocatable component.  The final routine deallocates this component, and we don't have the assignment overloaded.  The result is the array element is being finalized before the assignment occurs, and thus it ends up with a deallocated array.  If this is by design, then we will work with it, but I don't want to work around this issue if future compiler releases will handle it differently.

It seems like the correct way to handle this is to implement overloaded assignments along with final routines.

0 Kudos
Kevin_D_Intel
Employee
417 Views

gfotran 6.3 produces results supporting IanH's interpretation so it appears ifort is perhaps not handling the intrinsic case properly. I opened an internal defect report w/Development on this for them to analyze further.

(Internal tracking id: CMPLRS-42883)

0 Kudos
Horne__Steven
Beginner
417 Views

If I change the interface assignment operator to be a type-bound assignment operator, I obtain the same results as the intrinsic assignment operation above:

    module MyTypeModule
        implicit none
        
        type MyType
            real, allocatable, dimension(:) :: myArray
        contains
            final :: Finalize
            generic :: assignment(=) => GenericAssign
            procedure :: GenericAssign => MyTypeAssign
        end type MyType
        
    contains
        
        subroutine Finalize(this)
            type(MyType), intent(inout) :: this
            
            if (allocated(this%myArray)) deallocate(this%myArray)
        end subroutine Finalize
        
        subroutine MyTypeAssign(left,right)
            class(MyType), intent(out) :: left
            type(MyType), intent(in) :: right
            
            write(*,*) "Perform assignment"
            if (allocated(right%myArray)) left%myArray = right%myArray
        end subroutine MyTypeAssign
    end module MyTypeModule

    program TestCodeAssignmentFinalize
        use MyTypeModule
        implicit none

        type(MyType) :: a,b
    
        allocate(a%myArray(10))
        a%myArray = 1.0
        write(*,*) "a is allocated? ",allocated(a%myArray)
        write(*,*) "setting a = a"
        a = a
        write(*,*) "a is allocated? ",allocated(a%myArray)
        write(*,*) "b is allocated? ",allocated(b%myArray)
        write(*,*) "setting b = a"
        b = a
        write(*,*) "b is allocated? ",allocated(b%myArray)
    end program TestCodeAssignmentFinalize

And the output is:

 a is allocated?  T
 setting a = a
 Perform assignment
 a is allocated?  F
 b is allocated?  F
 setting b = a
 Perform assignment
 b is allocated?  F

This output is different from the interface assignment results, which is unexpected.

0 Kudos
Reply