Nested derived type with overloaded assignment
Asked Answered
N

2

8

I have a derived type (wrapper) containing an other derived type (over). For the latter the assignment operator have been overloaded. As the assignment of derived types happens per default componentwise, I'd expect that assigning two instances of wrapper would invoke the overloaded assignment for over at some point. However, using the program below, it does not seem to be the case. The overloaded assignment is only invoked if I also overload the assignment for wrapper containing an explicit assignment between instances of over (by uncommenting the commented code lines). Why? I find it somewhat counter intuitive. Is there any way to avoid the overloading in the wrapping type?

module test_module
  implicit none

  type :: over
    integer :: ii = 0
  end type over

  type :: wrapper
    type(over) :: myover
  end type wrapper

  interface assignment(=)
    module procedure over_assign
    !module procedure wrapper_assign
  end interface assignment(=)

contains

  subroutine over_assign(other, self)
    type(over), intent(out) :: other
    type(over), intent(in) :: self

    print *, "Assignment of over called"
    other%ii = -1

  end subroutine over_assign

  !subroutine wrapper_assign(other, self)
  !  type(wrapper), intent(out) :: other
  !  type(wrapper), intent(in) :: self
  !
  !  other%myover = self%myover
  !
  !end subroutine wrapper_assign

end module test_module

program test
  use test_module
  implicit none

  type(wrapper) :: w1, w2

  print *, "Assigning wrapper instances:"
  w2 = w1

end program test
Nursemaid answered 28/9, 2013 at 6:38 Comment(0)
D
11

This [unfortunate] situation is a consequence of the rules of the language (F90+) for intrinsic assignment of derived types. The details are spelled out in F2008 7.2.1p13. As a summary, intrinsic assignment of derived types (the assignment that happens with the wrapper_assign specific commented out) does not invoke non-type bound defined assignment for any components that are of derived type. In F90/F95, if you want defined assignment at some lower level of the component hierarchy then you need to have defined assignment for all the parent components up to the base object.

F2003 added type bound defined assignment to the language and this is invoked by intrinsic assignment of derived types. Use that instead of the stand-alone generic form of specifying defined assignment. (This also avoids a potential problem with the type name being accessible but the defined assignment procedure not being accessible.)

Dibbell answered 29/9, 2013 at 2:58 Comment(4)
Thank you very much Ian, I was not aware of those constraints for intrinsic assignment of derived types. Your suggestion indeed works. Unfortunately, the compiler I use the most, does not seem to implement that correctly, as it does not invoke the assignment of over, not even if I declare it as a type bound procedure (I'll file a bug report). But other compilers I've tried now indeed do it as you describe.Piegari
Do you really use correct syntax GENERIC :: ASSIGNMENT(=) => wrapper_assign?Chaco
@VladimirF: Yes, I guess I did. I posted my solution just to complete the thread. I've tried NAG 5.3 and GFortran 4.9.0, both with the expected results. Intel 13.1.3 on the other hand compiles the code wihtout complains, but the overloaded assignment is not invoked during program execution.Piegari
Works for me in Intel 14.0.Chaco
N
2

Just to complete the thread: the concrete realisation of IanH's suggestion (please upvote his original answer rather than this one) which worked for me was the following one:

module test_module
  implicit none

  type :: over
    integer :: ii = 0
  contains
    procedure :: over_assign
    generic :: assignment(=) => over_assign
  end type over

  type :: wrapper
    type(over) :: myover
  end type wrapper

contains

  subroutine over_assign(other, self)
    class(over), intent(out) :: other
    class(over), intent(in) :: self

    print *, "Assignment of over called"
    other%ii = -1

  end subroutine over_assign

end module test_module


program test
  use test_module
  implicit none

  type(wrapper) :: w1, w2

  print *, "Assigning wrapper instances:"
  w2 = w1

end program test
Nursemaid answered 29/9, 2013 at 20:29 Comment(1)
The class(over), intent(in) :: self should probably be TYPE(over), intent(in) :: self or derived types won't be allowed to override this operation.Myrtice

© 2022 - 2024 — McMap. All rights reserved.