Confused by finalization behaviour

Hi,
I am having a hard time understanding the behaviour of finalization. See the attached small code:
LinAlg1.F90 (2.2 KB)
Here is the output when running on an arm Mac with gfortran 14.2 ( I get a similar output under linux with the most recent intel compilers).

sibookpro:LinAlg_Class $ ./LinAlg1
Destroying empty
   No need to deallocate empty%data
Destroying u
   Deallocating u%data
Viewing u
   1.00000000       2.00000000       3.00000000     ...   3.00000000    
Destroying u
   Deallocating u%data
Destroying empty
   No need to deallocate empty%data
Destroying v
   Deallocating v%data
Viewing v
   2.33999991       2.33999991       2.33999991     ...   2.33999991    

Why is finalization called twice during creation?

Hi @Blaise,
When you use a function constructor, you return an object that serves as a rhs in your assignment

u = LinAlg_Type('u',x)

That object is very short lived and will be finalized once the lhs is allocated/assigned.

If you do not want to get this behavior you need to use subroutine constructors with intent out arguments.

You can have a look at this discussion. You will probably find some more details about ‘final’

1 Like

When the following statement is called
u = LinAlg_Type(‘u’,x)
actually two things occur:

  1. the code inside the function is executed, operating with the internal variable that the function “returns”
  2. assignment from this internal returning variable to the variable “u” declared within main program takes place.

So the “u” is finalized first (before the assignment), the second call is for finalizing the internal variable inside the function.

It helps to realize that when inside the function, the function is not working with the variable “u” because the function “does not know” what happens with the result (It could be used, for example, as an intermmediate in an expression).

1 Like

Adding to what others said:

Notice that, since you’re not using pointers, you don’t really need to worry about providing a final procedure.

The allocatable attribute implies automatic deallocation of any item when it goes out of scope.

1 Like

That’s correct, but note that the compiler is free to optimize this statement, for instance by not creating a temporary object but rather operating directly on u. In this case a single finalization would occur.

Thanks for all the comments. It looks like gfortran does not allow using subroutines for the constructor while ifx throws an unrelated error. See attached.
LinAlg2.F90 (2.4 KB)

No, the standard says that both finalizations occur. In the case there is a final subroutine that needs to be called then this is not an optimization the compiler is free to make.

My bad… I remember there is an assignment case where a finalization can be avoided by a smart compiler, but can’t remember which one.

Indeed, gfortran throws:

In generic interface 'linalg_type' at (1) procedures must be all FUNCTIONs as the generic name is also the name of a derived type

In this case, you can simply name your interface LinAlg:

interface LinAlg
   module procedure LinAlg_constructorArray,LinAlg_constructorLength
end interface LinAlg

Just check the call in your main program

u = LinAlg_Type('u',x)

should become

call LinAlg('u',x, u)

And what about using an initialization bound procedure:

type, public :: LinAlg_Type
    character(len=256)            :: name = 'empty'
    real,dimension(:),allocatable :: data
 contains
	  procedure, pass(self), private :: LinAlg_constructorArray
	  procedure, pass(self), private :: LinAlg_constructorLength
	  generic, public :: init => LinAlg_constructorArray,LinAlg_constructorLength
    procedure :: view    => LinAlg_view
    final     :: destroy
end type

that you call like this:

call v%init('v',3,2.34)