- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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?
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
@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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
"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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
That is correct - assuming the compiler has no bugs in this area.
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page