Polymorphic intent(out) arguments in pure subroutines
plevold opened this issue · 4 comments
The standard currently says the following about pure subroutines:
This means that the code below is not valid Fortran:
pure subroutine sub(x)
class(base_t), intent(out) :: x
end subroutine
The intent of this restriction is to avoid impure code being executed as a part of the pure subroutine. However, as this example demonstrates it is not sufficient a restriction to avoid impure code execution inside a pure subroutine:
module a_mod
implicit none
private
public base_t
public a_t
type, abstract :: base_t
contains
end type
type, extends(base_t) :: a_t
contains
final :: finalizer
end type
contains
subroutine finalizer(this)
type(a_t), intent(in) :: this
write(*,*) 'Impure finalizer invoked'
end subroutine
end module
program main
use a_mod, only: base_t, a_t
class(base_t), allocatable :: x
x = a_t()
write(*,*) 'Before pure sub'
call pure_sub(x)
write(*,*) 'After pure sub'
contains
pure subroutine pure_sub(x)
class(base_t), allocatable, intent(inout) :: x
if (allocated(x)) deallocate(x)
end subroutine
end program
As this restriction does not fulfill its purpose I think it should be removed. Polymorphic arguments with intent(out) is also very useful and it would be good to be able to use them in pure subroutines.
A possible solution:
- Add new syntax to abstract types for requiring that finalizers of any extending types must be pure. Could for example be something like this:
type, abstract, final(pure) :: base_t
end type
- Require that any polymorphic types used in such a way that a finalizer might be invoked inside a pure procedure must have the above mentioned attribute. This includes
- When used as local variables
- When used as allocatable dummy arguments with intent(inout)
- When used as dummy arguments with intent(out)
- Possibly some more situations?
What meaningful useful action could a pure
finalizer accomplish, though?
Better would be some means for disallowing extended types from being declared with final
procedures at all.
A pure finalizer could deallocate a pointer. It could also call to a pure bind(c)
procedure to deallocate memory allocated in a foreign language. How pure a bind(c)
procedure possibly could be is of course debatable, but most compilers does currently allow it (I have to admit I haven't checked what the standard has to say on this topic).
Both of these scenarios are highly relevant in order to build robust functionality without memory leaks in situations where one need to manage memory manually.
This is quite similar to #189
@everythingfunctional you are absolutely correct. Somehow that issue did not show up when I searched for this. I'll add my initial comment to that issue. I think this issue can be closed as it is a duplicate of #189.