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

Finalisation of Abstract Type

Diarmaid_d_
Beginner
869 Views

 

So I have an abstract type with allocatable length strings

type, abstract:: firstType
   character(len=:), allocatable:: one, two
  contains
end type

I want to be able to include a final  subroutine:

type, abstract:: firstType
    character(len=:), allocatable:: one
    
  contains
    final:: destroyFirst
end type

contains

subroutine destroyFirst(typeIn)
end subroutine

Is it possible?   When I try to use type(firstType) then I get 

 error #8313: The TYPE(derived-type-spec) shall not specify an abstract type.

but when I try to use class(firstType) I get the error

error #8339: The dummy argument of a final subroutine must be a variable of the derived type being defined and cannot be optional, pointer, allocatable, or polymorphic.

Is it possible to finalise an abstract type?

0 Kudos
11 Replies
Johannes_Rieke
New Contributor III
869 Views

Hi, although I cannot help you directly, you might find the answer while going through this:

http://fortranwiki.org/fortran/show/Factory+Pattern

I'm trying to get familiar with OO features at the moment and working through different examples. In the above mentioned example, replacing procedure::final by final::final, I get the same error #8339 as you.

Here an excerpt of the factory pattern example from Fortran Wiki:

  type CFactory
    private
        character(len=20) :: factory_type               !! Descriptive name for database
        class(Connection), pointer :: connection_type   !! Which type of database ?
    contains                                            !! Note 'class' not 'type' !
        procedure :: init                               !! Constructor
        procedure :: create_connection                  !! Connect to database
        procedure :: final                              !! Destructor
        ! final   :: final ! this does not work
  end type CFactory

It might work for you to take the procedure:: final approach? Hopefully I do not confuse you with my small knowledge on abstract types. Maybe I'm totally wrong.

0 Kudos
Steve_Lionel
Honored Contributor III
869 Views

No, the language does not permit an abstract type to have a finalizer because only entities of a declared type can be finalized and you can't declare something to be an abstract type. In your case I would suggest  making the type not abstract.

0 Kudos
Johannes_Rieke
New Contributor III
869 Views

Thanks Steve for the clarification. The finalization of type CFactory with 'final:: something' throws the error because of the pointer, although CFactory is not abstract itself, but only 'Connection'. Sorry for misusing this thread for my question.

0 Kudos
Diarmaid_d_
Beginner
869 Views

Thanks, Steve.  Unfortunately, I can't make my type non-abstract in my case (or rather, it would be too much work) because I defer a bunch of different subroutines, and (I believe) you can only have deferred subroutines with abstract types.  I'll probably just accept that I am leaking a bit of memory there.

This does seem to be a problem with the standard though, in that there should be a mechanism to finalise abstract types.   Presumably my use case is not the only time this will occur.   Or was the thinking that this wouldn't be common enough to support?

One way to do it at the moment is to include the deallocation in the final subroutines of any types extending the abstract type, but that stinks.  Another way is to have a second extension which is not abstract, but that stinks as well. 

Johannes, I don't believe that this " The finalization of type CFactory with 'final:: something' throws the error because of the pointer" is correct.   The error is thrown because finalisation of a polymorphic type isn't permitted.  To get the procedure final to work as a destructor, simply change it from class(CFactory) to type(CFactory).   You also seem a little confused the difference between "final:: <procedure name>" and "procedure:: final".   You might know this already, but the benefit of the first (final:: <proc_name>) is that you don't have to manually call it, it will be called whenever your object moves out of scope.   The second (procedure:: final) is (IMO) a confusingly named subroutine/function that you have to explicitly call yourself.

 

 

 

0 Kudos
FortranFan
Honored Contributor II
869 Views

@Diarmaid d.,,

A question: why do you even need to include a finalizer for the type you show that only has components with the ALLOCATABLE attribute?  Why not simply proceed with the benefits provided by this attribute?

Anyways, concrete types that extend the ABSTRACT types can include finalizers.

 

0 Kudos
Diarmaid_d_
Beginner
869 Views

"why do you even need to include a finalizer for the type you show that only has components with the ALLOCATABLE attribute?  Why not simply proceed with the benefits provided by this attribute?"

If you allocate (let's say an array) and the object later moves out of scope, then I believe that memory isn't freed?   Allocated memory is only freed if the allocated array is internal to the subroutine?

What I am trying to do here (ha, I may have fallen for the old XY problem) is to give each type a name, i.e. a string of unknown length.   Each of the different defined types extending my first type will have the name (hence it being defined in the abstract type), so I wanted to be able to deallocate that string when I finished with the object (edit: to prevent memory leaks).

Anyways, concrete types that extend the ABSTRACT types can include finalizers.

Of course, and as mentioned you could put the deallocate in each of the concrete types instead.   But I really don't like that solution, I think it is super prone to errors.

 

 

0 Kudos
FortranFan
Honored Contributor II
869 Views

Diarmaid d. wrote:

.. If you allocate (let's say an array) and the object later moves out of scope, then I believe that memory isn't freed?  .. to prevent memory leaks. ..

You seem to be worried about a problem with memory leaks with derived type components of ALLOCATABLE attribute that shouldn't be present with standard-conforming implementations.  Why don't you try to create a small reproducer first for a memory leaks issue with the ABSTRACT type in the original post?  If you notice a problem with Intel Fortran compiler, you should be able create a tracking incident with Intel support.

 

0 Kudos
Steve_Lionel
Honored Contributor III
869 Views

The memory will be freed when the variable goes out of scope. You really don't need finalizers just to deallocate allocatables - they are needed for pointers.

0 Kudos
Johannes_Rieke
New Contributor III
869 Views

Dear Diarmaid, you are totally right. My assumption with pointer is wrong. In the definition of the finalizer subroutine the passed dummy variable must not be defined as 'class(this)' but as 'type(this)'. Unfortunately, this is also an error/typo in Chapman's very nice book (Fortran 95/2003 for Scientists and Engineers) in example 16-2. Changing 'class(vector)' to 'type(vector)' compilation and execution runs fine.

Gfortran (7.1) and Intel Fortran (17.4) give very similar and clear error messages, if class but not type is used. However, took me some time to realize how to fix this.

0 Kudos
Diarmaid_d_
Beginner
869 Views

Ah ok - I've received different advice from different people about this.   But if I am reading you correctly, then any allocated components should be freed when the type goes out of scope - i.e. you shouldn't have any memory leaks from allocated components of derived types, regardless of whether or not you have a final subroutine.   Is this right?

0 Kudos
Steve_Lionel
Honored Contributor III
869 Views

That is correct - assuming the compiler has no bugs in this area.

0 Kudos
Reply