(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