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

COMPILER BUG? duplicate call to final subroutine for object construction by ifort

DataScientist
Valued Contributor I
1,208 Views

The following code, when compiled with ifort, calls the final subroutine of the `test_type` object twice just to construct the object. GNU Fortran compiler (does not call the final routine at all apparently).

module test_mod

    type :: test_type
        integer :: unit = -huge(0)
    contains
        final :: finalize
    end type

    interface test_type
        module procedure :: constructTest
    end interface

contains

    function constructTest(file) result(test)
        character(*), intent(in) :: file
        type(test_type) :: test
        open(newunit = test%unit, file = file)
    end

    subroutine finalize(test)
        type(test_type), intent(inout) :: test
        logical :: opened
        print *, "this final subroutine should not be called!"
        inquire(unit = test%unit, opened = opened)
        if (opened) close(test%unit)
    end

end module

use test_mod

logical :: opened
type(test_type) :: test
test = test_type("test.txt")
inquire(unit = test%unit, opened = opened)
print *, opened
end
I suspect ifort's behavior is a compiler bug.
But I am not sure if gfortran's behavior is standard-conforming either.
Ideally, I'd expect the constructor to open the requested file and
not call the final subroutine upon returning the object
so that the file remains open for later usage.
But ifort closes the file by calling the final subroutine.
gfortran has the expected behavior.
Any help is greatly appreciated.
Here is the example code in action:
0 Kudos
1 Solution
jimdempseyatthecove
Honored Contributor III
1,180 Views

I suspect that line 35 creates a temporary test_type object on the stack for use in the copy operation to the local variable test, then the destruction of the stack object calls the final which closes the unit as indicated in both the stack copy and the lhs copy, but leaves the state variable opened in the lhs alone.. What you may need to do (though it may or may not meet your requirements) is to create a copy operator(=) that sets the rhs opened to .false. (after the copy).

 

Jim Dempsey

View solution in original post

4 Replies
jimdempseyatthecove
Honored Contributor III
1,181 Views

I suspect that line 35 creates a temporary test_type object on the stack for use in the copy operation to the local variable test, then the destruction of the stack object calls the final which closes the unit as indicated in both the stack copy and the lhs copy, but leaves the state variable opened in the lhs alone.. What you may need to do (though it may or may not meet your requirements) is to create a copy operator(=) that sets the rhs opened to .false. (after the copy).

 

Jim Dempsey

FortranFan
Honored Contributor III
1,162 Views

Intel Fortran behavior is indeed as stated in the standard where in an intrinsic assignment, a finalizable object on the LHS gets finalized before being defined using the function result and the object(s) corresponding to the evaluation of the expr on RHS get finalized also.

As alluded to by @jimdempseyatthecove , you need a different approach:

  • consider using some setter method(s) toward initialization of your derived type with suitable actions (such as resource allocations, etc. including file connections) and
  • avoid so-called "constructors" i.e., the use of a generic interface with the same name as the derived type to functions that imitate object construction - you will find they are more trouble than they are worth. 
IanH
Honored Contributor III
1,124 Views

Defined assignment can help here - as the copy semantics of intrinsic assignment don't match your requirements.  You probably want move semantics.

If you have a type in Fortran that is representing an resource of some sort (in your case a file), you pretty much always need defined assignment.  Often that implies that if you have a type with a finalizer (which is there to manage the cleanup of a resource), you need defined assignment.

(Defined assignment can hinder in other ways, or bring other requirements with it.)

DataScientist
Valued Contributor I
1,119 Views

Thank you all. I agree that a defined assignment is the ultimate clean solution. For now, I managed to get the problem solved by adding an internal private flag to the type that keeps track of the calls made to the constructor.

The forum does not allow me to edit the title of this page, which now appears to be incorrect (this is not an ifort bug).

0 Kudos
Reply