This is the mail archive of the
fortran@gcc.gnu.org
mailing list for the GNU Fortran project.
Re: Ambiguities with generic interfaces (and an ICE)
Hello,
this is a new version of my program. gfortran 4.6 compiles it and the program
runs, but there are two problems:
- In add_vector_2d I need to deallocate the result at the second invocation
That seems incorrect to me.
- For the point3d case: the third coordinate is nicely changed, but
the first two
(set via the point2d "parent" component) are not.
I have not been able to pinpoint the source of the problem yet.
Regards,
Arjen
----
! random_walk.f90 --
! Simulate a random walk in two and three dimensions
!
! Problem gfortran:
! - with both arguments class(..) add_vector_2d and add_vector_3d ambiguous
! - with vector type(...) error on operator(+): class(...) actual arguments
!
module points2d3d
use trace
implicit none
type point2d
real :: x, y
contains
procedure :: print => print_2d
procedure :: add_vector => add_vector_2d
procedure :: random => random_vector_2d
procedure :: assign => assign_2d
generic, public :: operator(+) => add_vector
generic, public :: assignment(=) => assign
end type point2d
type, extends(point2d) :: point3d
real :: z
contains
procedure :: print => print_3d
procedure :: add_vector => add_vector_3d
procedure :: random => random_vector_3d
procedure :: assign => assign_3d
!! generic, public :: operator(+) => add_vector
!! generic, public :: assignment(=) => assign
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
subroutine random_vector_2d( point )
class(point2d) :: point
call random_number( point%x )
call random_number( point%y )
point%x = 2.0 * point%x - 1.0
point%y = 2.0 * point%y - 1.0
end subroutine random_vector_2d
!
! This routine gets confused for the 2D variant
! - essentially the same interface?
subroutine random_vector_3d( point )
class(point3d) :: point
call point%point2d%random
call random_number( point%z )
point%z = 2.0 * point%z - 1.0
end subroutine random_vector_3d
function add_vector_2d( point, vector )
class(point2d), intent(in) :: point, vector
class(point2d), allocatable :: add_vector_2d
if ( allocated(add_vector_2d) ) then
deallocate( add_vector_2d )
endif
allocate( 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
class(point2d), intent(in) :: vector
class(point3d), allocatable :: vector_3d
class(point2d), allocatable :: add_vector_3d
allocate( vector_3d )
select type (vector)
class is (point3d)
vector_3d%point2d = point%point2d + vector%point2d
vector_3d%z = point%z + vector%z
end select
call move_alloc( vector_3d, add_vector_3d )
end function add_vector_3d
subroutine assign_2d( left, right )
class(point2d), intent(inout) :: left
class(point2d), intent(in) :: right
left%x = right%x
left%y = right%y
end subroutine assign_2d
subroutine assign_3d( left, right )
class(point3d), intent(inout) :: left
class(point2d), intent(in) :: right
select type (right)
type is (point3d)
left%point2d = right%point2d
left%z = right%z
end select
end subroutine assign_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 = 3 ! Was 10
integer :: i
integer :: trial
real :: deltt = 0.1
! Select what type of point ...
do trial = 1,2
if (trial == 1) then
write(*,*) 'Two-dimensional walk:'
point => point_2d
vector => vector_2d
else
! Now let's take a 3D walk ...
write(*,*) 'Three-dimensional walk:'
point => point_3d
vector => vector_3d
end if
call point%random
do i = 1,nsteps
call vector%random
point = point + vector
call point%print
enddo
enddo
end program random_walk