(j3.2006) Question regarding the ambiguity of procedures with polymorphic arguments

Tobias Burnus burnus
Wed May 11 09:32:14 EDT 2011


Dear all,

I have a question whether the following procedures is ambiguous (as one 
compiler claims) or not (3 compilers and an older version of the first 
one accept it). After initially believing that the program is valid, I 
now think that it invalid. I would be happy if someone could confirm or 
disprove this.

In the following, the type point3d extends point2d. The interfaces of 
the two functions are:

   function add_vector_2d( point, vector )
     class(point2d), intent(in)  :: point
     class(point2d), intent(in)  :: vector

   function add_vector_3d( point, vector )
     class(point3d), intent(in)  :: point
     type(point3d), intent(in)   :: vector


The reason I believe that they are ambiguous is:

"Two dummy arguments are distinguishable if [...] neither is TKR
compatible with the other" (F2008, 12.4.3.4.5)

For an actual argument of the type "class(point3d),type(point3d)",
either function has the correct interface. More precisely,
class(point2d) is type compatible* with class(point3d) - and
class(point2d) is type compatible with type(point3d).

The crucial word is "neither": While add_vector_3d's dummies are
not type compatible to add_vector_2d - the reverse is not true.
Thus, the arguments are not distinguishable.

(* A polymorphic entity that is not an unlimited polymorphic entity is
type compatible with entities of the same declared type or any of its
extensions.", F2008, 4.3.1.3.)

Tobias

PS: Full example by Arjen Markus. Note, there is also a polymorphic assignment, which makes the program definitely invalid - but it does not matter regarding the question above.


module points2d3d     implicit none

     type point2d         real :: x, y     contains         procedure   
             :: print           => print_2d         procedure           
     :: add_vector      => add_vector_2d         generic, public         
:: operator(+)     => add_vector     end type point2d

     type, extends(point2d) :: point3d         real :: z     contains   
       procedure               :: print                     => print_3d 
         procedure               :: add_vector_3dversion      => 
add_vector_3d         generic, public         :: add_vector_new         
    => add_vector_3dversion         generic, public         :: 
operator(+) => add_vector_3dversion     end type point3d

contains subroutine print_2d( point )     class(point2d) :: point

     write(*,'(2f10.4)') point%x, point%y end subroutine print_2d

subroutine print_3d( point )     class(point3d) :: point

     write(*,'(3f10.4)') point%x, point%y, point%z end subroutine print_3d

function add_vector_2d( point, vector )     class(point2d), intent(in) 
  :: point     class(point2d), intent(in)  :: vector     type(point2d)   
             :: add_vector_2d

     add_vector_2d%x = point%x + vector%x     add_vector_2d%y = point%y 
+ vector%y

end function add_vector_2d

function add_vector_3d( point, vector )     class(point3d), intent(in) 
  :: point     type(point3d), intent(in)   :: vector

     type(point3d)               :: add_vector_3d

     add_vector_3d%point2d = point%point2d + vector%point2d     
add_vector_3d%z       = point%z       + vector%z

end function add_vector_3d

end module points2d3d

program random_walk

     use points2d3d   ! Both 2D and 3D points available

     type(point2d), target   :: point_2d, vector_2d     type(point3d), 
target   :: point_3d, vector_3d

     !     ! A variable of class point2d can point to point_2d but     ! 
also to point_3d     !     class(point2d), pointer :: point, vector

     integer        :: nsteps = 100     integer        :: i     integer 
        :: trial     real           :: deltt  = 0.1

     ! Select what type of point ...     point => point_2d     vector => 
vector_2d

     do trial = 1,2         if ( trial == 1 ) then             
write(*,*) 'Two-dimensional walk:'         else             write(*,*) 
'Three-dimensional walk:'         endif

         call random_vector( point )

         do i = 1,nsteps             call random_vector( vector )

             point = point + vector

             call print_point( point )         enddo

         ! Now let's take a 3D walk ...

         point => point_3d         vector => vector_3d

     enddo
end program random_walk




More information about the J3 mailing list