This is the mail archive of the fortran@gcc.gnu.org mailing list for the GNU Fortran project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]