Search code examples
pointersfortrangfortranassignment-operator

Fortran assignment overload with pointers


I want to overload the assignment for a type that I want to use for polymorphic pointers. I dont know the actual subtype the pointer is holding on runtime. But the following example code reproduces the strange compiler error I get:

module example

type :: base_class
    real(4) :: some_garbage
contains

end type

type, extends(base_class) :: sub_class
    real(4) :: even_more_garbage
contains

end type

type :: main_operations_t
    class(base_class), pointer :: basic_pointer
    class(base_class), pointer :: pointer_array(:)
contains
    procedure :: main_operations
end type

interface assignment(=)
    module procedure assign_base_class
end interface

contains

subroutine assign_base_class(result_object, input_object)
implicit none
    class(base_class), pointer, intent(out) :: result_object
    class(base_class), pointer, intent(in) :: input_object
    result_object%some_garbage = input_object%some_garbage
end subroutine

subroutine main_operations(this)
implicit none
    class(main_operations_t) :: this
    class(base_class), pointer :: hack

    allocate(this%basic_pointer)
    allocate(this%pointer_array(2))

    this%basic_pointer%some_garbage = 0.0
    this%pointer_array(1)%some_garbage = 1.0
    this%pointer_array(2)%some_garbage = 2.0

    this%basic_pointer = this%pointer_array(1)
    this%pointer_array(1) = this%pointer_array(2)
    this%pointer_array(2) = this%basic_pointer

    this%basic_pointer = this%pointer_array(1)
    hack => this%pointer_array(1)
    hack = this%pointer_array(2)
    hack => this%pointer_array(2)
    hack = this%basic_pointer
end subroutine

end module

When I try to assign to the indexed pointer array i.e

this%pointer_array(1) = this%pointer_array(2)
this%pointer_array(2) = this%basic_pointer

I use gfortran 4.8.4 on Ubuntu. I get a compiler error:

Error: Variable must not be polymorphic in intrinsic assignment at (1) - check that there is a matching specific subroutine for '=' operator

The assignment to the 0d pointer however works without complaints. The section with the "hack" pointer shows a possible workaround to get this to work in an ugly manner.


Solution

  • The compiler is complaining it needs a defined assignment. You do have one, but it requires pointers:

    subroutine assign_base_class(result_object, input_object)
        class(base_class), pointer, intent(out) :: result_object
        class(base_class), pointer, intent(in) :: input_object
    

    (It is not necessary to repeat implicit none in all module procedures. I'd argue it is a clutter which harms readability.)

    And your variables are not pointers. pointer_array(1) is NOT a pointer even though pointer_array is a pointer.

    A solution is to remove the unneeded pointer attribute:

    subroutine assign_base_class(result_object, input_object)
        class(base_class), intent(out) :: result_object
        class(base_class), intent(in) :: input_object
        result_object%some_garbage = input_object%some_garbage
    end subroutine
    

    This compiles cleanly.

    It would make sense to have the pointer attribute there if you were doing pointer assignment, but as it stands, there is no use of it in the defined assignment.