Search code examples
oopfortran

Giving a generic subroutine to a structure as its containing procedure


When using Object Oriented structures in Fortran, I am trying to assign a generic function to a structure as follows:

    !>================================================
    type:: PropEq
    !>------------------------------------------------     
        real(dp) :: coeffs(4)      
        contains               
            procedure, pass :: compute => computePhysicalProperty    
    !>------------------------------------------------     
    end type PropEq
    !>================================================

With the interface of the generic subroutine as follows:

    !!>================================================
    interface computePhysicalProperty
    !!>------------------------------------------------ 
        module procedure computePhysicalProperty_scalar 
        module procedure computePhysicalProperty_array
    !!>------------------------------------------------ 
    end interface computePhysicalProperty
    !!>================================================  

And the two functions:

    !>================================================
    function computePhysicalProperty_scalar(propEq, T) result(value)
    !>------------------------------------------------ 
        real(dp) :: value
        
        class(PropEqAbstract) :: propEq
        real(dp), intent(in) :: T
        real(dp), allocatable :: a(:)
        
        a = propEq% coeffs
        
        value = a(1) + a(2)*T + a(3)*T*T + a(4)*T*T*T

    !>------------------------------------------------  
    end function computePhysicalProperty_scalar
    !>================================================
    
    !>================================================
    function computePhysicalProperty_array(propEq, T) result(value)
    !>------------------------------------------------ 
        real(dp) :: value
        
        class(PropEqAbstract) :: propEq
        real(dp), intent(in), allocatable :: T(:)
        real(dp), allocatable :: a(:)
        
        a = propEq% coeffs
        
        value = a(1) + a(2)*T + a(3)*T*T + a(4)*T*T*T

    !>------------------------------------------------  
    end function computePhysicalProperty_array
    !>================================================

Essentially, I am trying to overload the procedure to allow both scalar and array inputs to the function.

When doing so, I get the following error:
error #8182: The name is neither an abstract interface nor a procedure with an explicit interface. [COMPUTEPHYSICALPROPERTY]

Additionally, I have found the following which seems to work: Generic type-bound procedures with procedure arguments

   !>================================================
    type:: PropEq
    !>------------------------------------------------     
        real(dp) :: coeffs(4)      
        contains               
            procedure, pass :: compute_scalar => computePhysicalProperty_scalar
            procedure, pass :: compute_array => computePhysicalProperty_array
            generic :: compute => compute_scalar, compute_array    
    !>------------------------------------------------     
    end type PropEq
    !>================================================

Why do the procedures need to be declared explicitely in the type?

Is there a way to use an interface to reduce the type to the following?

????? :: compute => computePhysicalProperty

Thank you

Compiler: Intel
IDE: Visual Studio Enterprise


Solution

  • What you tried to do is not allowed by the Fortran language standard. A binding cannot point to a generic interface, it must point to a procedure. Once you have the bindings (type=bound procedures) in your type, you can make a generic binding from them using the generic :: compute =>.

    The standard grammar is the following:

    R748 type-bound-proc-binding
             is type-bound-procedure-stmt
             or type-bound-generic-stmt
             or final-procedure-stmt
    

    From that you are interested in

    R749 type-bound-procedure-stmt
         is PROCEDURE [ [ , binding-attr-list ] :: ] type-bound-proc-decl-list
         or PROCEDURE (interface-name), binding-attr-list :: binding-name-list
    

    and then

    R750 type-bound-proc-decl     is     binding-name [ => procedure-name ]
    

    with a constraint

    C774 (R750) The procedure-name shall be the name of an accessible module procedure or an external procedure
        that has an explicit interface.
    

    That is the ultimate restriction that you are hitting. A procedure name must a name of a procedure, not of a generic procedure.

    Note: if => procedure-name does not appear, it is as though => procedure-name had appeared with a procedure name the same as the binding name.