j3-fortran / fortran_proposals

Proposals for the Fortran Standard Committee
175 stars 14 forks source link

Polymorphic intent(out) arguments in pure subroutines #287

Open plevold opened 1 year ago

plevold commented 1 year ago

The standard currently says the following about pure subroutines: image

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:

  1. 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
  2. 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?
klausler commented 1 year ago

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.

plevold commented 1 year ago

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.

everythingfunctional commented 1 year ago

This is quite similar to #189

plevold commented 1 year ago

@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.