masayoshiz
masayoshiz

Reputation: 13

Why Fortran/gfortran assume the UNKNOWN type?

I have a grammar question about Fortran. It seems that Fortran (or gfortran?) cannot assume a returning value of a function defined in an interface block in an abstract interface. I tried to compile the following codes by gfortran (version 9.4.0).

abstract_class.f90:

module module_abstract_class
    implicit none

    type, public, abstract :: abstract_class
        contains
        procedure(method_interface), pass(self), deferred :: method
    end type

    abstract interface
        pure function method_interface(self, func, a, b) result(ret)
            import abstract_class
            class(abstract_class), intent(in) :: self
            real                 , intent(in) :: a, b
            real                              :: ret

            interface
                pure function func(a, b) result(ret)
                    real, intent(in) :: a, b
                    real             :: ret
                end function
            end interface

        end function
    end interface
end module

extend_class.f90:

module module_extend_class
    use module_abstract_class

    implicit none

    type, extends(abstract_class) :: extend_class
        contains
        procedure, public, pass(self) :: method
    end type

    contains

    pure function method(self, func, a, b) result(ret)
        class(extend_class), intent(in) :: self
        real               , intent(in) :: a, b
        real                            :: ret

        interface
            pure function func(a, b) result(ret)
                real, intent(in) :: a,b
                real             :: ret
            end function
        end interface

        ret = func(a, b)
    end function method
end module

main.f90:

program i_love_fortran
    use module_extend_class

    type(extend_class) :: e

    print *, e%method(add, 1, 2)

contains

    pure function add(a, b) result(ret)
        real, intent(in) :: a, b
        real             :: ret
        ret = a + b
    end function
end Program i_love_fortran

shell:

gfortran abstract_class.f90 extend_class.f90 main.f90

But, I could not compile this code due to the following errors.


gfortran abstract_class.f90 extend_class.f90 main.f90 extend_class.f90:8:17:

8 |         procedure, public, pass(self) :: method
  |                 1

Error: Argument mismatch for the overriding procedure ‘method’ at (1): Type mismatch in argument 'func' (UNKNOWN/REAL(4)) extend_class.f90:6:49:

6 |     type, extends(abstract_class) :: extend_class
  |                                                 1

Error: Derived-type ‘extend_class’ declared at (1) must be ABSTRACT because ‘method’ is DEFERRED and not overridden main.f90:2:8:

2 |     use module_extend_class
  |        1

Fatal Error: Cannot open module file ‘module_extend_class.mod’ for reading at (1): No such file or directory compilation terminated.


I think "func" defined in "method" should be REAL(4). Why does Fortran/gfortran assume that "func" is UNKNOWN type?

Upvotes: 1

Views: 143

Answers (1)

Federico Perini
Federico Perini

Reputation: 1416

Your func is just another abstract interface, because id defines what the actual pure function will be like when the function called. So, you should include it just as also an abstract interface and make it public so other modules can access it. Then, you reference it as a function dummy argument using

procedure(func_template) :: func

This now works:

module module_abstract_class
    implicit none

    type, public, abstract :: abstract_class
        contains
        procedure(method_interface), pass(self), deferred :: method
    end type

    interface
    end interface

    abstract interface
        pure function func_template(a, b) result(ret)
            real, intent(in) :: a, b
            real             :: ret
        end function func_template
    
        pure function method_interface(self, func, a, b) result(ret)
            import abstract_class,func_template
            class(abstract_class), intent(in) :: self
            real                 , intent(in) :: a, b
            procedure(func_template)          :: func
            real                              :: ret

        end function
    end interface
end module


module module_extend_class
    use module_abstract_class

    implicit none

    type, extends(abstract_class) :: extend_class
        contains
        procedure, public, pass(self) :: method
    end type

    contains

    pure function method(self, func, a, b) result(ret)
        class(extend_class), intent(in) :: self
        real               , intent(in) :: a, b
        procedure(func_template)        :: func
        real                            :: ret

        ret = func(a, b)
    end function method
end module


program i_love_fortran
    use module_extend_class

    type(extend_class) :: e

    print *, e%method(add, 1.0, 2.0)

contains

    pure function add(a, b) result(ret)
        real, intent(in) :: a, b
        real             :: ret
        ret = a + b
    end function
end Program i_love_fortran

Upvotes: 0

Related Questions