- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
In just want to confirm if this is the expected behavior of a finalizer.
In the code below,
module tes_final_mod implicit none type :: my_final integer :: n contains final :: destroy end type my_final contains subroutine destroy(self) type(my_final) :: self write(*,*), 'Destroy executed!' end subroutine destroy end module tes_final_mod !============================= program tes_finalizer use tes_final_mod implicit none type(my_final), allocatable :: a(:), b(:) type(my_final), allocatable :: c ! allocate(a(10)) a%n= 1 deallocate(a) print*, 'a deallocated' allocate(a(10)) a%n= 3 allocate(b(20)) b(1:10)= a call move_alloc(b, a) print*, 'b deallocated' allocate(c) c%n= 2 deallocate(c) print*, 'c deallocated' call call_final contains subroutine call_final type(my_final) :: aa print*, 'SUB: Will finalize when returned.' return end subroutine call_final end program tes_finalizer
I have the following result, when compiled with ifort Version 15.0.3.187 Build 20150407:
a deallocated b deallocated Destroy executed! c deallocated SUB: Will finalize when returned. Destroy executed!
That is, the finalizer only runs when SCALAR allocatable objects are deallocated (object c in the main and aa in the subroutine). Allocatable arrays are not finalized either by directly killing then with a deallocate (array a, first time) or by the move_alloc (array b).
Is this the expected behavior?
Even stranger, when the very same program is compiled with gfortran, the results are almost the same, with the exception of the last call on the finalizer, when the subroutine is exited. With gfortran the return statement did not cause the finalizer to run.
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Never mind. Now I understand what's written in Metcalf's book:
A final subroutine for a type must be a module procedure with a single dummy argument
of that type. All the final subroutines for that type form a generic set and must satisfy the
rules for unambiguous generic references; since they each have exactly one dummy argument
of the same type, this simply means that the dummy arguments must have different kind
type parameter values or rank. Each such dummy argument must be a variable without the
All I need to do is add another procedure on the FINAL :: list. The new procedure must have an array dummy argument:
subroutine destroy_arr(self) type(my_final) :: self(:) write(*,*) 'Destro_arr executed!' end subroutine destroy_arr
Now the new finalizer is called both by the deallocate(a) and move_alloc(b,a).
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
With the recent compiler release, you may find use of an impure elemental procedure for the finalizer helpful, as it will be selected regardless of the rank of the entity being finalized.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
ianh wrote:
With the recent compiler release, you may find use of an impure elemental procedure for the finalizer helpful, as it will be selected regardless of the rank of the entity being finalized.
Ok, thanks. Soon I'l upgrade the compiler to version 16.
I forgot to mention that the executable compiled with gfortran still fails to run the finalizer on returning from the subroutine. Perhaps it's a bug on gfortran's implementation?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I think there are bugs with both ifort and gfortran in this area. With a modified test program (so the letters refer to different things), ifort fails to finalize the allocatable entity initially designated by `c` that is deallocated when the allocation of `b` is moved across to `c` (4.5.6.3p1). gfortran recent trunk fails to finalize the rank one array section of `b` when it is assigned to with the value of `c` (4.5.6.3p9). This is in addition to your observation that gfortran fails to finalize the local variable `aa` of the internal procedure in your example (which is likely related to the fact that `aa` is neither referenced or defined in that internal procedure, and so the compiler perhaps pretends it doesn't exist) (4.5.6.3p2). These observations are consistent regardless of whether multiple non-elemental finalizers are used, or a single impure elemental finalizer is used.
module tes_final_mod implicit none type :: my_final integer :: n = 0 contains final :: destroy_scalar final :: destroy_rank1_array end type my_final contains subroutine destroy_scalar(self) type(my_final), intent(inout) :: self write (*,"(A,1X,I0)"), 'Destroy executed!', self%n end subroutine destroy_scalar subroutine destroy_rank1_array(self) type(my_final), intent(inout) :: self(:) integer :: i do i = 1, size(self) write (*,"(A,1X,I0)"), 'Destroy executed!', self(i)%n end do end subroutine destroy_rank1_array end module tes_final_mod program test_finalizer use tes_final_mod implicit none type(my_final), allocatable :: a(:), b(:), c(:) type(my_final), allocatable :: d allocate(a(3)) a%n = 1 deallocate(a) ! (3 * n = 1) print*, 'a deallocated' allocate(b(8)) b%n = 2 allocate(c(4)) c%n = 3 b(1:4) = c ! (4 * n = 2) <<<<< gfortran print *, 'c assigned to part of b' call move_alloc(b, c) ! (4 * n = 3) <<<<< ifort print*, 'allocation of b moved to c' allocate(d) d%n = 4 deallocate(d) ! (1 * n = 4) print*, 'd deallocated' call call_final ! c is still allocated here, but note the language standard specifies ! that it is NOT finalized when the program terminates. contains subroutine call_final type(my_final) :: aa aa%n = 5 print*, 'SUB: Will finalize when returned.' return end subroutine call_final ! (1 * n = 5) end program test_finalizer
(Note windows variant of ifort, but I'd be surprised if behaviour was different for the other operating systems.)
>ifort /check:all /warn:all /standard-semantics "2015-09-07 final.f90" && "2015-09-07 final.exe" Intel(R) Visual Fortran Intel(R) 64 Compiler for applications running on Intel(R) 64, Version 16.0 Build 20150815 Copyright (C) 1985-2015 Intel Corporation. All rights reserved. Microsoft (R) Incremental Linker Version 10.00.40219.01 Copyright (C) Microsoft Corporation. All rights reserved. "-out:2015-09-07 final.exe" -subsystem:console "2015-09-07 final.obj" Destroy executed! 1 Destroy executed! 1 Destroy executed! 1 a deallocated Destroy executed! 2 Destroy executed! 2 Destroy executed! 2 Destroy executed! 2 c assigned to part of b allocation of b moved to c Destroy executed! 4 d deallocated SUB: Will finalize when returned. Destroy executed! 5
In the above, I expect to see "Destroy executed! 3" four times immediately before the "allocation of b moved" message.
I will report the gfortran observations to its developers.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Dear IanH.
This is the output of your program compiled in linux (Fedora 22) with ifort V. 15.0.3.187 Build 20150407, without any compilation option:
Destroy executed! 1 Destroy executed! 1 Destroy executed! 1 a deallocated Destroy executed! 19227248 Destroy executed! 0 Destroy executed! 4 Destroy executed! 0 c assigned to part of b allocation of b moved to c Destroy executed! 4 d deallocated SUB: Will finalize when returned. Destroy executed! 5
As you reported, it fails to finalize b after calling move_alloc(b,c). However, in one of my tests, I've defined the finalizer:
subroutine destroy_arr(self) type(my_final) :: self(:) write(*,*) 'Destroy_arr executed!' end subroutine destroy_arr
without the intent(inout) and in this case, it is called after the move_alloc.
Another behavior that I've noticed and find strange is that the finalizer is called after a simple copy operation, like your
b(1:4) = c
Is this expected? To run the finalizer after a copy operation? Moreover, note the strange values of n reported by the routine. It seems that the program creates a temporary allocation array of type my_final with random values of n, and these are the ones that are destroyed.
This is the output obtained with gfortran, again with no options:
Destroy executed! 1 Destroy executed! 1 Destroy executed! 1 a deallocated c assigned to part of b Destroy executed! 3 Destroy executed! 3 Destroy executed! 3 Destroy executed! 3 allocation of b moved to c Destroy executed! 4 d deallocated SUB: Will finalize when returned. Destroy executed! 5
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
rudi-gaelzer wrote:
Another behavior that I've noticed and find strange is that the finalizer is called after a simple copy operation, like your
b(1:4) = cIs this expected? To run the finalizer after a copy operation? Moreover, note the strange values of n reported by the routine. It seems that the program creates a temporary allocation array of type my_final with random values of n, and these are the ones that are destroyed.
Yes - finalization is invoked for intrinsic assignment, see F2008 4.5.6.3p9. Conceptually the lifetime of the value that the array section variable b(1:4) held prior to the assignment comes to an end with that assignment. Note that you don't need deallocation in order to get finalization.
I am using 16.0 initial release. I do not see strange values of n for my test cases. If you are going to use the newer language features, you will want to be as current as possible.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I reported the defect to Development that IanH noted with ifort in post #5. The same incorrect results noted in the post occur on Linux with 16.0.
(Internal tracking id: DPD200375877)
(Resolution Update on 02/23/2016): This defect is fixed in the Intel® Parallel Studio XE 2016 Update 2 Release (PSXE 2016.2.062/ CnL 2016.2.181 - Linux)
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
The finalization defect (detailed in post #5) has been fixed in the recently released Intel® Parallel Studio XE 2016 Update 2 release (PSXE 2016.2.062/ CnL 2016.2.181 - Linux).
![](/skins/images/872293744008A34B36F8ABF94A46CC66/responsive_peak/images/icon_anonymous_message.png)
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page