PetrH
PetrH

Reputation: 730

"Passed-object dummy argument must be a scalar"

I have type-bound procedures which I want to accept an array as their passed dummy argument (getMean and assignEachThatInThis below). This does not compile though. I have read Metcalf et al. and they do not say that the passed dummy argument must be scalar and I don't really understand why that would have to be the case anyway.

If I use the nopass attribute it does compile and so it does when the procedures are not type-bound ones.

Can someone, please, explain what is going on and what is and is not safe to do?

Here is my example:

module types
implicit none

integer, parameter :: DP = selected_real_kind(r=250,p=13)

type :: my_type1

        real(KIND=DP), dimension(:),   allocatable :: elem1    ! interest rate

    contains

        procedure :: getMean        => getMean_my_type1 

        procedure ::                   assignThatInThis_my_type1
        procedure ::                   assignEachThatInThis_my_type1
        generic   :: assignment (=) => assignThatInThis_my_type1, assignEachThatInThis_my_type1

end type my_type1

contains

subroutine assignThatInThis_my_type1(this,that)
        ! Defines the overloaded `=` operator for the 'my_type1' class
        ! this = that

   class(my_type1), intent(inout) :: this
   class(my_type1), intent(in)    :: that

   this%elem1  = that%elem1

end subroutine assignThatInThis_my_type1

subroutine assignEachThatInThis_my_type1(this,that)
        !--> this is apparently illegal, 'this' has to be a scalar :-(
        !--> in principle it could work with the 'nopass' attribute (see 'getMean_my_type1') but that won't work with the assignment operator '='

   class(my_type1), dimension(:), intent(inout) :: this
   class(my_type1), dimension(:), intent(in)    :: that

   integer :: i

   do i = 1,size(this,1)
      this(i) = that(i)
   end do

end subroutine assignEachThatInThis_my_type1


subroutine getMean_my_type1(this,that)

   class(my_type1), dimension(:), intent(inout) :: this
   class(my_type1),               intent(inout) :: that

   integer :: nTypes
   integer :: n
   integer :: j

   nTypes = size(this,1)
   n      = size(this(1)%elem1,1)    ! length of the simulation

   ! sum all elem1
   do j = 1,nTypes
      that%elem1 = that%elem1 + this(j)%elem1
   end do

   ! divide by the number of elements
   that%elem1 = that%elem1 / real(nTypes)

end subroutine getMean_my_type1


end module types


program pdatest
implicit none


end program pdatest

The following works, where I use the nopass attribute for getMean and don't have the assignment subroutines type-bound:

type :: my_type1

        real(KIND=DP), dimension(:),   allocatable :: elem1    ! interest rate

    contains

         procedure, nopass :: getMean        => getMean_my_type1

end type my_type1


interface assignment (=)
        module procedure assignEachThatInThis_my_type1, assignThatInThis_my_type1
end interface

Upvotes: 1

Views: 402

Answers (1)

francescalus
francescalus

Reputation: 32451

To start, the passed-object dummy is required to be scalar (among other things) directly because of the rules of Fortran. Consider F2008, C456:

The passed-object dummy argument shall be a scalar, nonpointer, nonallocatable dummy data object with the same declared type as the type being defined; ...

With the nopass attribute the type-bound procedure reference has no passed-object, so this restriction does not apply. Equally, if you make the subroutine reference not from its type binding, the restriction doesn't apply.

With the getMean binding, the desire is to reduce an array to a scalar, but with the assignment the wish is to have an input array and an output array of the same shape. This latter is a case for an elemental subroutine.

Upvotes: 1

Related Questions