[J3] Clarification needed on finalization
Brad Richardson
everythingfunctional at protonmail.com
Thu Jan 18 18:55:51 UTC 2024
Hi Mark,
I agree that the standard seems not to say anything specifically about this particular aspect. I'm tempted to suggest that this should be processor dependent, with a slight modification to the example for demonstration purposes.
```
module repro
type finalizable
integer :: i
contains
final :: print_finalized
end type
type t
type(finalizable),allocatable :: x
end type
contains
subroutine print_finalized(x)
type(finalizable),intent(inout) :: x
print *,"finalizing t(finalizable)", x%i
end subroutine
end module
use repro
type(t) :: a(2)
! assume that each of a's x components have been allocated previously somewhere
a = [t(x=finalizable(1)), t(x=finalizable(2))]
end
```
The finalizer is definitely called twice for the lhs of the assignment. Now, there are 3 more times that the finalizer could be called twice, but I think it might be desirable not to require it for optimization purposes.
It could be called to finalize the whole array constructed on the rhs, but it might be a valid optimization if the definition of each element happen directly to the elements of x, rather than constructing a temporary array and performing a copy. I'll note that this would not be valid in all cases (i.e. if x appears on the rhs).
It could be called to finalize each of the `t` objects created in the array constructor, but it might be a valid optimization that the space for the array has already be reserved and the definition of each element happen directly, rather than create a temporary for each constructor. This is totally independent of the previous consideration.
It could be called to finalize each of the `finalizable` objects created and passed to the `t` constructors, but again it might be a valid optimization that the space for each `t` has already been reserved and the definition of each component happens directly, rather than create a temporary for each. This again is totally independent of the previous two considerations.
I do think this all warrants a discussion.
Regards,
Brad
On Thu, 2024-01-18 at 16:46 +0000, Mark LeAir via J3 wrote:
> Hi Everyone,
>
> One of the Flang developers forwarded me the following question below. Can anyone clarify this with the current Standard? Or do I need to submit an Interp for the next meeting?
>
> Thanks,
>
> Mark
>
> I was looking at a test failure with flang and the expected behavior is not clear to me.
>
> With structure constructors and array constructors, it is possible to create values of a derived type with allocatable components. These values are neither named, nor function results.
>
> Fortran 2023 does not really say when and if such components are automatically deallocated in section 9.7.3.2 Deallocation of allocatable variables.
>
> So, it is not clear how to exactly apply the sentence related to finalization in the same section: “If an allocatable component is a subobject of a finalizable object, any final subroutine for that object is executed before the component is automatically deallocated.”
>
> Obviously, the compiler should deallocate the memory of such temporary to avoid leaks after use, but it is not clear to me if this qualifies as Fortran “automatic deallocation”. Otherwise, why shouldn’t we also finalize it when making a temporary in a copy-in/copy-out situation.
>
> So, my question is, given a type `with_finalizable_alloc_comp`, that has some allocatable component `alloc_comp` with a final routine `finalizer`, how many times should `finalizer` be called in something like `print *, [with_finalizable_alloc_comp(alloc_comp=1), with_finalizable_alloc_comp(alloc_comp=2)]`?
>
> Depending on how you implement and read things, I think this could currently be anything in 0 times, 2 times or 4 times.
>
> Rational:
>
> - 0 time: this is neither a function result/named variable and no paragraph in 9.7.3.2 apply.
>
> - 2 times: finalize the “whole expression” (that is, and expression that is an actual argument or does not appear in a parent expression). Tempting but badly defined in my opinion.
>
> - 4 times: regard a structure constructor and an array constructor as functions returning values and apply 9.7.3.2 for `array_ctor(struct_ctor(1), struct_ctor(2))`. Well defined, but probably not optimal.
>
> I would advocate for 0 time.
>
> Here is a reproducer:
>
> ```
>
> module repro
>
> type finalizable
>
> integer :: i
>
> contains
>
> final :: print_finalized
>
> endtype
>
> type t
>
> type(finalizable),allocatable :: x
>
> endtype
>
> contains
>
> subroutine sub(x)
>
> type(t),intent(in) :: x(2)
>
> print *,"in sub"
>
> endsubroutine
>
> subroutine print_finalized(x)
>
> type(finalizable),intent(inout) :: x
>
> print *,"finalizing t(finalizable)", x%i
>
> endsubroutine
>
> endmodule
>
> use repro
>
> call sub([t:: t(x=finalizable(1)), t(x=finalizable(2))])
>
> end
>
> ```
>
> - ifx (and flang currently): call finalizer 0 times.
>
> - gfortran and nagfor: call finalizer 2 times.
>
> - xlf: call finalizer 4 times.
>
> So… some clarification is needed here I think.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mailman.j3-fortran.org/pipermail/j3/attachments/20240118/25a53090/attachment-0001.htm>
More information about the J3
mailing list