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

How can data in an abstract class be deleted?

Daniel_Dopico
New Contributor I
711 Views

A FINAL procedure cannot be written for that matter, as it requires the object passed as TYPE, and an ABSTRACT type cannot be instanced.

The reason for wanting a FINAL procedure is to correctly delete some data initialized and used inside. This data is used in some other non-DEFERRED procedures that must be inherited by the children classes.

The non-DEFERRED procedures cannot be moved to any derived class, since the DEFERRED procedure is not defined until the very last class in the hierarchy. Therefore all the chain is ABSTRACT until the last TYPE, implemented by the library user.

0 Kudos
1 Solution
IanH
Honored Contributor III
605 Views

During the finalization process of an object of extended type, the parts of the object that belong to the extension "go-away" first, before the parts belonging to the parent type.  If the final procedure for the parent type could take polymorphic objects, then it could invoke deferred bindings that are implemented by the extension type - the procedures associated with those bindings could then work with components that are no longer there.  This doesn't make sense - so it is prohibited.

You can either wrap the data up in a separate type that is used as a component of your abstract type - as you have done, or you can wrap it up in a non-abstract parent type of the abstract type. 

  ...
  type concrete
     integer:: i
   contains
     FINAL:: destructor_concrete
  end type concrete

  type, extends(concrete), abstract :: eqObject_abs
   contains
     procedure(iface_eq_object), pass, deferred :: eq_object
  end type eqObject_abs
  ...

With the above, the characteristics of type `concrete` (its components, bindings etc) become a subset of the characteristics of type `eqObject_abs` (an object of type `eqObject_abs` "is a" object of type `concrete`).  If that's philosophically not what you want, then consider retaining your existing composition approach.

View solution in original post

4 Replies
jimdempseyatthecove
Honored Contributor III
658 Views

Can you encapsulate the abstract type within a defined type that has a FINAL that handles the deletion of the abstract type?

 

Jim Dempsey

0 Kudos
Daniel_Dopico
New Contributor I
644 Views

Thank you Jim.

In that way it doesn't make sense the abstract type because we want to keep the deferred. Maybe you want to say the other way round: encapsulating the data in a type with FINAL and include the encapsulated data in the abstract type. This is what I am doing (see below), but I was wondering if there is any other way to do it. It is annoying not having the possibility of making FINAL in ABSTRACT types.

module test

  type concrete
     integer:: i
   contains
     FINAL:: destructor_concrete
  end type concrete


  type, abstract :: eqObject_abs !< equal unlimited polymorphic type
     type(concrete) :: ct
   contains
     procedure(iface_eq_object), pass, deferred :: eq_object
  end type eqObject_abs

  abstract interface
     subroutine iface_eq_object(this)
       import
       class(eqobject_abs):: this
     end subroutine iface_eq_object
  end interface

  type, extends(eqobject_abs):: usuario
   contains
     procedure, pass :: eq_object => usuarioimpl
  end type usuario

contains

  subroutine destructor_concrete(this)
    type(concrete)::this

    print *, "i'm called"
  end subroutine destructor_concrete

  subroutine usuarioimpl(this)
    class(usuario):: this

    print *, "deferred call"
  end subroutine usuarioimpl

  subroutine doit()
    implicit none
    type(usuario):: u

    call u%eq_object()
  end subroutine doit

end module test

program main
  use test
  implicit none

  call doit()
end program main
 

 

0 Kudos
IanH
Honored Contributor III
606 Views

During the finalization process of an object of extended type, the parts of the object that belong to the extension "go-away" first, before the parts belonging to the parent type.  If the final procedure for the parent type could take polymorphic objects, then it could invoke deferred bindings that are implemented by the extension type - the procedures associated with those bindings could then work with components that are no longer there.  This doesn't make sense - so it is prohibited.

You can either wrap the data up in a separate type that is used as a component of your abstract type - as you have done, or you can wrap it up in a non-abstract parent type of the abstract type. 

  ...
  type concrete
     integer:: i
   contains
     FINAL:: destructor_concrete
  end type concrete

  type, extends(concrete), abstract :: eqObject_abs
   contains
     procedure(iface_eq_object), pass, deferred :: eq_object
  end type eqObject_abs
  ...

With the above, the characteristics of type `concrete` (its components, bindings etc) become a subset of the characteristics of type `eqObject_abs` (an object of type `eqObject_abs` "is a" object of type `concrete`).  If that's philosophically not what you want, then consider retaining your existing composition approach.

Daniel_Dopico
New Contributor I
506 Views

Thank you for the alternative, Ian, we haden't thought of this way for organizign the types.

0 Kudos
Reply