• Module procedures and abstract interfaces

    From Rudi Gaelzer@21:1/5 to All on Tue Apr 5 09:42:00 2022
    I have a comment/question regarding the mechanism provided by the standard to store a number of identical interfaces and the level of verbosity involved.

    Say I write a bunch of functions, all with the same interface and the same function result. The only difference involved are the methods employed to evaluate the same function.

    One of the things I can do in this case is to create a module, with a single INTERFACE block containing the interfaces of the different implementations inside it. If I declare the interfaces with the "module function" keywords I can write the source
    codes inside a submodule, with the header "module procedure" for each individual function code.

    This works very well and is very useful. The only irksome thing here is that the interface block inside the module ended up containing several almost identical declarations, whose only differences were the actual names of the various functions.
    Then I thought of declaring an abstract interface and then only include the list of the proper names inside the interface block with the PROCEDURE(<abst inter>) declaration, in order to achieve a lower verbosity level. But it seems that the standard
    forbids this alternative.

    This is the sample code: !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! MODULE module_procedures_abstract_interface
    use, intrinsic :: iso_fortran_env, only: dp => real64
    implicit none

    ABSTRACT INTERFACE
    function fun_2_args(x, y)
    import :: dp
    real(dp) :: fun_2_args
    real(dp), intent(in) :: x, y
    end function fun_2_args
    END INTERFACE

    ! INTERFACE ! version 1
    ! PROCEDURE(fun_2_args) :: fun1, fun2
    ! END INTERFACE

    INTERFACE ! version 2
    module function fun1(x,y)
    ! import :: dp
    real(dp) :: fun1
    real(dp), intent(in) :: x, y
    end function fun1
    !***
    module function fun2(x,y)
    ! import :: dp
    real(dp) :: fun2
    real(dp), intent(in) :: x, y
    end function fun2
    END INTERFACE
    END MODULE module_procedures_abstract_interface !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

    Compilation with version 1 commented works all right, but if I uncomment version 1, error messages appear. The intel compiler gives:
    ifort -c module_procedures_abstract_interface_MOD.f90
    module_procedures_abstract_interface_MOD.f90(16): error #6651: The PROCEDURE specification is allowed only if the interface-block has a generic-spec.
    PROCEDURE(fun_2_args) :: fun1, fun2
    ---^
    compilation aborted for module_procedures_abstract_interface_MOD.f90 (code 1)

    So it seems to me that I only have the more verbose solution allowed.
    Or am I missing something?

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From FortranFan@21:1/5 to rgae...@gmail.com on Tue Apr 5 11:29:01 2022
    On Tuesday, April 5, 2022 at 12:42:03 PM UTC-4, rgae...@gmail.com wrote:

    ..
    So it seems to me that I only have the more verbose solution allowed.
    Or am I missing something?

    @rgae...@gmail.com,

    First, you may want to post this at Fortran Discourse also: https://fortran-lang.discourse.group/

    Two benefits with this:
    1) you are dealing with modern Fortran code specifically and it will be much easier for you and anyone else interested to read and follow the details,
    2) you will get a wider engagement and feedback on such matters

    Your concerns with verbosity are valid, you may bring it up at GitHub J3-Fortran proposals site by posting a thread under Issues and see where that leads:
    https://github.com/j3-fortran/fortran_proposals

    In the mean time, note a slightly modified approach you can consider is with procedure pointer and you might find it is a tad less verbose in terms of repeated INTERFACE declarations - see below (with a simple function example):

    module implementations_m
    contains
    function fun1(x,y) result(z)
    integer, intent(in) :: x
    integer, intent(in) :: y
    integer :: z
    z = x + y
    end function
    function fun2(x,y) result(z)
    integer, intent(in) :: x
    integer, intent(in) :: y
    integer :: z
    z = 2*x + 3*y
    end function
    end module
    module m
    use implementations_m
    abstract interface
    function Ifun(x,y) result(z)
    integer, intent(in) :: x
    integer, intent(in) :: y
    integer :: z
    end function
    end interface
    procedure(Ifun), pointer :: fun => null() ! or set to default
    contains
    subroutine setfun( fun_name )
    character(len=*), intent(in) :: fun_name
    select case ( fun_name )
    case ( "fun1" )
    fun => fun1
    case ( "fun2" )
    fun => fun1
    case default
    ! error stop?
    end select
    end subroutine
    end module
    use m
    call setfun( "fun2" )
    print *, fun(3, 4)
    end

    So with above, your SUBMODULE approach is eschewed and the interface and implementation are separated out in a way as suggested since Fortran 90 revision.

    To reiterate, I recommend you initiate a dialogue on this at Fortran Discourse.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Rudi Gaelzer@21:1/5 to FortranFan on Tue Apr 5 15:15:00 2022
    On Tuesday, April 5, 2022 at 3:29:04 PM UTC-3, FortranFan wrote:
    On Tuesday, April 5, 2022 at 12:42:03 PM UTC-4, rgae...@gmail.com wrote:

    ..
    So it seems to me that I only have the more verbose solution allowed.
    Or am I missing something?
    @rgae...@gmail.com,

    First, you may want to post this at Fortran Discourse also: https://fortran-lang.discourse.group/

    Two benefits with this:
    1) you are dealing with modern Fortran code specifically and it will be much easier for you and anyone else interested to read and follow the details,
    2) you will get a wider engagement and feedback on such matters

    Will do that, thanks for the suggestion.


    Your concerns with verbosity are valid, you may bring it up at GitHub J3-Fortran proposals site by posting a thread under Issues and see where that leads:
    https://github.com/j3-fortran/fortran_proposals

    Might do that as well, thanks.


    In the mean time, note a slightly modified approach you can consider is with procedure pointer and you might find it is a tad less verbose in terms of repeated INTERFACE declarations - see below (with a simple function example):

    module implementations_m
    contains
    function fun1(x,y) result(z)
    integer, intent(in) :: x
    integer, intent(in) :: y
    integer :: z
    z = x + y
    end function
    function fun2(x,y) result(z)
    integer, intent(in) :: x
    integer, intent(in) :: y
    integer :: z
    z = 2*x + 3*y
    end function
    end module
    module m
    use implementations_m
    abstract interface
    function Ifun(x,y) result(z)
    integer, intent(in) :: x
    integer, intent(in) :: y
    integer :: z
    end function
    end interface
    procedure(Ifun), pointer :: fun => null() ! or set to default
    contains
    subroutine setfun( fun_name )
    character(len=*), intent(in) :: fun_name
    select case ( fun_name )
    case ( "fun1" )
    fun => fun1
    case ( "fun2" )
    fun => fun1
    case default
    ! error stop?
    end select
    end subroutine
    end module
    use m
    call setfun( "fun2" )
    print *, fun(3, 4)
    end

    So with above, your SUBMODULE approach is eschewed and the interface and implementation are separated out in a way as suggested since Fortran 90 revision.

    To reiterate, I recommend you initiate a dialogue on this at Fortran Discourse.

    Yes, I thought about using a procedure pointer. Your setfun routine is a nice idea, will think about it as well.
    I guess that with submodules, there is no way the standard will allow my imagined implementation. In this case, your suggestion works better for my objectives, as long as I only declare the pointer and setfun as public and all the rest as private, in
    order to achieve the desired data abstraction.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)