SOUser
SOUser

Reputation: 3852

How to declare the interface section for a procedure argument, which in turn references to a user-derived type of the same module?

As the following code sample shows, person_list is a user-derived type and contains a type-bound procedure compare_persons. I would like compare_persons to be able to accept a certain group of compareFunc as one of its arguments, and therefore declare the interface section for compareFunc. Note the first argument of compareFunc is of type person_list. (As you might tell, person_list is like TStringList in Delphi's VCL.)

The compilation cannot proceed. The error messages are:

[root@localhost new]# ifort -c lib1.f90 
lib1.f90(26): error #6457: This derived type name has not been declared.   [PERSON_LIST]
                    TYPE(person_list) :: persons    !   error #6457: This derived type name has not been declared.   [PERSON_LIST]
-------------------------^
lib1.f90(23): error #6404: This name does not have a type, and must have an explicit type.   [PERSONS]
                FUNCTION compareFunc(persons, index1, index2)    !   error #6404: This name does not have a type, and must have an explicit type.   [PERSONS] 
-------------------------------------^
compilation aborted for lib1.f90 (code 1)

The error messages seem to indicate a circular reference between modules? I am therefore wondering how to declare the interface section for a procedure argument, which in turn references to a user-derived type of the same module? Any insights will be appreciated!

PS: The reason to try this module is the preference of OO programing style. The reason to try fortran is a big code base.

PS: The compiler is Intel Fortran Compiler, and the version is as the follows:

[root@localhost new]# ifort --version
ifort (IFORT) 12.1.0 20111011
Copyright (C) 1985-2011 Intel Corporation.  All rights reserved.

The code sample is:

MODULE lib1

    TYPE person_list

    CONTAINS
        PROCEDURE, PASS :: compare_persons

    END TYPE

CONTAINS

    FUNCTION compare_persons(this, index1, index2, compareFunc)

        IMPLICIT NONE

        INTEGER :: compare_persons
        CLASS(person_list) :: this
        INTEGER, INTENT(IN) :: index1
        INTEGER, INTENT(IN) :: index2

        INTERFACE
            FUNCTION compareFunc(persons, index1, index2)    !   error #6404: This name does not have a type, and must have an explicit type.   [PERSONS] 
                IMPLICIT NONE
                INTEGER :: compareFunc
                TYPE(person_list) :: persons    !   error #6457: This derived type name has not been declared.   [PERSON_LIST]
                INTEGER :: index1
                INTEGER :: index2
            END FUNCTION compareFunc
        END INTERFACE

        compare_persons = compareFunc(this, index1, index2)

    END FUNCTION compare_persons

END MODULE lib1

tpg2114 figures out the solution!

MODULE lib1

    TYPE person_list

    CONTAINS
        PROCEDURE, PASS :: compare_persons

    END TYPE

    INTERFACE
        FUNCTION CompareFuncInterface(persons, index1, index2)  
            IMPORT person_list
            IMPLICIT NONE
            INTEGER :: CompareFuncInterface
            TYPE(person_list), INTENT(IN) :: persons    
            INTEGER, INTENT(IN) :: index1
            INTEGER, INTENT(IN) :: index2
        END FUNCTION CompareFuncInterface
    END INTERFACE

CONTAINS

    FUNCTION compare_persons(this, index1, index2, compareFunc)

        IMPLICIT NONE

        INTEGER :: compare_persons
        CLASS(person_list), INTENT(IN) :: this
        INTEGER, INTENT(IN) :: index1
        INTEGER, INTENT(IN) :: index2
        PROCEDURE (CompareFuncInterface) :: compareFunc

        compare_persons = compareFunc(this, index1, index2)

    END FUNCTION compare_persons

END MODULE lib1

Upvotes: 1

Views: 2126

Answers (1)

tpg2114
tpg2114

Reputation: 15100

Okay, I figured it out:

MODULE lib1

   TYPE :: persons
   CONTAINS
      PROCEDURE, PASS :: compare_persons
   END TYPE persons

   INTERFACE
      INTEGER FUNCTION compareFunc_interface(personsIn, index1, index2)
         IMPORT persons
         IMPLICIT NONE
         TYPE(persons), INTENT(IN) :: personsIn
         INTEGER, INTENT(IN) :: index1
         INTEGER, INTENT(IN) :: index2 
      END FUNCTION compareFunc_interface
   END INTERFACE


CONTAINS 
   FUNCTION compare_persons(this, index1, index2, compareFunc)
      IMPLICIT NONE

      INTEGER :: compare_persons
      CLASS(persons) :: this
      INTEGER :: index1
      INTEGER :: index2
      PROCEDURE(compareFunc_interface) :: compareFunc
   END FUNCTION compare_persons
END MODULE lib1

From the 2003 standard, the IMPORT statement brings a definition from the host scoping unit to the local scoping unit. If you were using something from a different module, the INTERFACE would need a USE statement. But since you are importing from the higher up scoping unit, you use IMPORT and a list of the things you would like to bring into that scope

Edit

Also note, I added PASS to the declaration of the type-bound procedure. Although not required (because this is the default action), I prefer to always put PASS or NOPASS so that the intention is always explicit. This helps both the programmer (making sure they do what they think they are doing) and anybody who reads the code.

Upvotes: 5

Related Questions