3
votes

Goal: use the subroutine load_things to load a library of structures of type su2.

Running gfortran simple.f90 produces

Undefined symbols for architecture x86_64:
  "_load_things_", referenced from:
      _MAIN__ in cc7DuxGQ.o
      (maybe you meant: ___myclass_MOD_load_things_sub)
ld: symbol(s) not found for architecture x86_64
collect2: error: ld returned 1 exit status

The main program follows:

program simple
  use myClass
  implicit none
  integer :: nThings
  type ( su2 ) :: reflections
      call load_things ( nThings, reflections )
end program simple

The module definition is:

module myClass
implicit none
type :: su2
    integer :: matrix_obj ( 1 : 2, 1 : 2 )
contains
    private
    procedure, nopass, public :: load_things => load_things_sub
end type su2

private load_things_sub
contains
    subroutine load_things_sub ( nThings, U )
        integer,      intent ( out ) :: nThings
        type ( su2 ), intent ( out ), allocatable :: U ( : )
            nThings = 2
            allocate ( U ( nThings ) )
            U ( 1 ) % matrix_obj = reshape ( [ 0, 1, 1, 0 ], [ 2, 2 ] )
            U ( 2 ) % matrix_obj = reshape ( [ 0, 1, 1, 0 ], [ 2, 2 ] )
    end subroutine load_things_sub

end module myClass

The following web pages were studied without success: Correct use of modules, subroutines and functions in fortran,

Fortran 90 - to transmit values from main subroutine to the functions and other subroutines,

Fortran: Calling a function in a module from a procedure in another module,

Fortran 90 How to call a function in a subroutine in a module?

2

2 Answers

3
votes

As Vladimir F comments load_things is a binding name of the derived type reflections. It isn't, as the answer says, the name of a subroutine.

As, then, IanH says, you could change your code to

call load_things_sub ( nThings, reflections )

but you'll also need to make that a public entity of the module. You're probably wanting to use the type-bound way so that it can remain private (the binding of the type itself being accessible):

call reflections%load_things(nThings, reflections)

Which brings up another set of points: you can't do the above.

You're using nopass for the binding as the dummy argument of the type is an allocatable array: you can't use pass. However, in your main program the dummy argument reflections is a non-allocatable scalar: there's a mismatch there so call load_things_sub(nThings, reflections) isn't valid.

Further

type ( su2 ), allocatable :: reflections(:)
call reflections%load_things ( nThings, reflections )

itself isn't valid. First, for call reflections%... reflections must be allocated. Second, with reflections an array nopass isn't allowed for the binding.

Where does that leave you? Well, you'll have to fix the allocatability of reflections, but the easiest thing to do is possibly to just go along with making load_things_sub public and stick with the first path, getting rid of the type-bound procedure.

2
votes

Your module doesn't have a subroutine named load_things - it has a subroutine named load_things_sub. Choose the correct variant of the name, and then correct the name in the other statement appropriately.

Subsequent to this answer being initially submitted, the OP added a private statement to the module that makes the load_things_sub inaccessible in scopes using the module. In the absence of other information that private statement should be deleted.

It makes little sense to reference procedures such as load_thing_sub through a binding. Just reference it as a normal procedure.

Note that many of the listed references are for Fortran 90. Bindings were introduced with Fortran 2003.