Mikael Morin wrote:
What if only comp's subcomponents are finalizable, the finalization
wrapper should still be called, shouldn't it?
Well, that's handled in the "else" branch. There, I walk all
subcomponents. I do not need to walk them in case there is a finalizer
as the called finalization wrapper will handle them.
Actually, I don't understand why you walk twice over the subcomponents:
in the else branch here and in the finalizer.
Well, I only walk once per component. However, I could unconditionally
call this function – and move some of the checks from the main program here.
If comp has finalizable subcomponents, it has a finalization wrapper,
which is (or should be) caught above, so this branch is (or should be)
unreachable.
I probably miss something, but I don't see why this branch should be
unreachable. One has:
if (component is allocatable)
call DEALLOCATE(comp) ! which might invoke finalizers
else if (component itself has a finalizer)
call FINAL_WRAPPER
else
for all nonpointer subcomponents which are allocatables, have
finalizers or have allocatable/finalizable components, call
finalize_component.
end if
I expected something like:
if (allocatable)
call deallocate (comp)
else if (finalizer or subcomponents have a finalizer)
call FINAL_WRAPPER
Well, the question is whether one wants to call a finalize wrapper for a
simple "comp%alloctable_int(10)" or not. In the current scheme, I tried
to avoid calling a finalizer wrapper for simple allocatable components.
Thus, one has the choice:
a) Directly call DEALLOCATE for alloctable components of subcomponents
b) Always call the finalizer wrapper – also for nonalloctable TYPEs
(with finalizable/allocatable components)
(a) is more direct and possibly a bit faster while (b) makes the wrapper
function a tad smaller.
As said above, I don't understand why you would walk over the components
twice
I don't. I touch every ((sub)sub)component only once; I only do a deep
walk until there is either no component or a pointer or an allocatable
or a finalizable component. I do acknowledge that I repeat some of the
logic by handling the outer component in the wrapper and the inner
(sub)subcomponents in the final_components.
+ else if (comp->ts.type == BT_CLASS && CLASS_DATA (comp)
+ && CLASS_DATA (comp)->attr.allocatable)
+ alloc_comp = true;
Shouldn't one assume without condition that there are allocatable or
finalizable subcomponents when there is a polymorphic component?
Well, we do not deallocate/finalize polymorphic POINTER components.
Indeed, then I prefer having !CLASS_DATA(comp)->attr.pointer.
Okay, that's equivalent; though, I have to admit that I prefer the
current version, which I regard as cleaner.
* * *
Regarding the flag or nonflag final_comp, I have to admit that I still
do not completely understand how you would implement it.
One option would be something like the following
bool has_final_comp(derived) {
for (comp = derived->components; comp; comp = comp->next)
{
if (comp->attr.pointer)
continue;
if (comp->f2k_derived->finalizers || comp->ts.type == BT_CLASS)
return true;
if (comp->ts.type == BT_DERIVED
&& has_final_comp(comp->ts.u.derived))
return true;
}
return false
}
in class.c
Another is the version which gets set in parse.c.
However, I do not understand what you mean by:
If performance is a problem, the function could use the flag as a
backend. As long as the field is used and set in a single place, I
don't mind. I don't have a strong opinion either, there is already a
full bag of flags; one more wouldn't make things dramatically worse.
Tobias