Generic type bound assignment with polymorphic variables

Generic type bound assignment with polymorphic variables

Using Release 7 of version 12.1, I'm trying to define a generic assignment function for a polymorphic variable. The following code demonstrates a couple of problems I'm having:

!=====================================================
module a_module
implicit none
private
public :: a_t

type a_t

contains

procedure, public :: assign

generic :: assignment(=) => assign

end type a_t

contains

subroutine assign(to, from)
class(a_t), intent(inout) :: to
class(a_t), intent(in) :: from

end subroutine assign

end module a_module

module b_module
use a_module
implicit none
private
public :: b_t

type, extends(a_t) :: b_t

contains

procedure, public :: assign

generic :: assignment(=) => assign

end type a_t

contains

subroutine assign(to, from)
class(b_t), intent(inout) :: to
class(b_t), intent(in) :: from

end subroutine assign

end module b_module

program main

use a_module
use b_module

implicit none

class(a_t), allocatable :: v1
class(a_t), allocatable :: v2

allocate(b_t::v1)
allocate(b_t::v2)

v2 = v1

end program
!=====================================================

The code as-is does not compile, giving me an error 8383. Shouldn't the code work as written?

If I change the name of the "assign" subroutine in b_module to something else (say, "assignb"), the code compiles and runs. However, when it reaches the statement "v2 = v1", it executes the subroutine assign in a_module. I would expect it to execute assignb in b_module. Is this behavior expected?

Thanks,
Doug

6 posts / 0 new
Last post
For more complete information about compiler optimizations, see our Optimization Notice.

I can reproduce this - once I correct the typo in the declaration of b_t. The second problem, where it calls the a_t assignment, is I think one I've seen before, though I thought we had fixed it. I will check. I need to study the standard a bit before I comment on the first problem (error 8383).

Steve - Intel Developer Support

Steve,
I found the error in what I sent you earlier. Consider the following:

!=====================================================
module a_module
implicit none
private
public :: a_t

type a_t

contains

procedure, public :: assign

generic :: assignment(=) => assign

end type a_t

contains

subroutine assign(to, from)
class(a_t), intent(inout) :: to
class(a_t), intent(in) :: from

end subroutine assign

end module a_module

module b_module
use a_module
implicit none
private
public :: b_t

type, extends(a_t) :: b_t

contains

procedure, public :: assign

end type b_t

contains

subroutine assign(to, from)
class(b_t), intent(inout) :: to
class(a_t), intent(in) :: from ! Previous error: needs to be of the same type as the overridden procedure

end subroutine assign

end module b_module

program main

use a_module
use b_module

implicit none

class(a_t), allocatable :: v1
class(a_t), allocatable :: v2

allocate(b_t::v1)
allocate(b_t::v2)

call v2%assign(v1)
v2 = v1

end program
!=====================================================

As per the comment, the "from" dummy argument needs to be of the same type as the overridden procedure.

The code now compiles, but the resulting performance doesn't seem to be correct. I would expect that the two lines "call v2%assign(v1)" and "v2 = v1" would execute the same procedure (the b_t type-bound procedure "assign"). The first line does this; the second executes the a_t "assign" function.

Yes, I see this behavior. We'll look into it and get back to you.

Steve - Intel Developer Support

Sorry for the delay - I have escalated this as issue DPD200175845. The compiler is using the "declared type" of v1 and v2 rather than the dynamic type.

I believe the error message for the original code is correct, since you give the routines the same name. Here is a modified version of the code which shows how this sort of thing is supposed to be done, though it still doesn't do what is wanted.

module a_module
  implicit none
  private
  public :: a_t

  type a_t
    contains
      procedure, public :: assign_a
      generic :: assignment(=) => assign_a
  end type a_t

  contains

  subroutine assign_a(to, from)
    class(a_t), intent(inout) :: to
    class(a_t), intent(in) :: from
    print *, "In assign_a"
  end subroutine assign_a

end module a_module

module b_module
  use a_module
  implicit none
  private
  public :: b_t

  type, extends(a_t) :: b_t
    contains
      procedure, public :: assign_b
      generic :: assignment(=) => assign_b
  end type b_t

  contains

  subroutine assign_b(to, from)
    class(b_t), intent(inout) :: to
    class(b_t), intent(in) :: from   
    print *, "In assign_b"

  end subroutine assign_b

end module b_module


program main

use a_module
use b_module

implicit none

class(a_t), allocatable :: v1
class(a_t), allocatable :: v2

allocate(b_t::v1)
allocate(b_t::v2)

v2 = v1

end program

Steve - Intel Developer Support

Hi Steve. I have a similar question (see: http://software.intel.com/en-us/forums/topic/328732#comment-1681634) I see that the dereferencing of assignment based on declared type is standard-conforming. But is there another way of implementing a generic container which would be able to add values to storage from the declared class or any of its subclasses?

Thanks

Evgeniy

Leave a Comment

Please sign in to add a comment. Not a member? Join today