4

I have an interface block to define a generic subroutine which have an assumed size array as dummy argument (in order to be able to act on 'the middle' of a passed array, like a C pointer) and it does not compile. Here is simple exemple:

module foo

  interface sub
     module procedure isub
     module procedure dsub
  end interface

  contains

  subroutine isub(a,n)
    integer, intent(in) :: a(*), n
    integer :: i
    print*, 'isub'
    do i=1,n
     print*, a(i)
    enddo
  end subroutine isub

  subroutine dsub(a)
    real(8), intent(in) :: a(*)
    integer, intent(in) :: n
    integer :: i
    print*, 'dsub'
    do i=1,n
     print*, a(i)
    enddo
  end subroutine dsub

end module foo

program test

  use foo

  implicit none

  integer :: ai(4)
  real(8) :: ad(4)

  ai=(/1,2,3,4/)
  ad=(/1.,2.,3.,4./)

  call sub(ai,3)
  call sub(ad,3)

  call isub(ai(2),3)
  !call sub(ai(2),3)

end program test

The commented line does not compile, whereas it is ok when calling directly the subroutine with call isub(ai(2),3) (tested with gfortran and ifort). Why and is it possible to have it to work with call sub(ai(2),3)?

edit: with ifort, it says:

$ ifort overload.f90
overload.f90(37): error #6285: There is no matching specific subroutine for this generic subroutine call.   [SUB]
  call sub(ai(2),3)
-------^
compilation aborted for overload.f90 (code 1)

Thanks

janou195
  • 1,175
  • 2
  • 10
  • 25

1 Answers1

6

You are passing a scalar to a function that is expecting an array. Try

call sub(ai(2:2))

which is passing an array of length one. I'm wondering why call isub(ai(2)) is accepted, though...

To answer your new question (partly in the comments):

If you restrict yourself to contiguous arrays, you can use call sub(ai(2:4)) without loss of performance using deferred shape arrays:

subroutine isub(a)
  integer,intent(in) :: a(:)
  integer            :: i

  print*, 'isub'
  do i=1,size(a)
    print*, a(i)
  enddo
end subroutine isub

There are no temporary arrays created with ifort or gfortran. You can check for this using:

  • ifort -check arg_temp_created

  • gfortran -Warray-temporaries

Alexander Vogt
  • 17,879
  • 13
  • 52
  • 68
  • 1
    My exemple wa not very good (I have now edited it) but in my real application, I don't want to pass a single element but the adress of any element of the caller's array from which the subroutine will start to process, like I would do with a C pointer. And I don't want to use slice which involve temporary copy – janou195 Jun 18 '14 at 16:42
  • 1
    Why? You are programming in Fortran, not in C?! – Alexander Vogt Jun 18 '14 at 16:45
  • Are you trying to write a subroutine for arrays of different *dimensions* (e.g. vectors and matrices)? – Alexander Vogt Jun 18 '14 at 16:49
  • You know that Fortran usually passes arguments by reference, right? There's no need for pointers for what (I think) you are trying to achieve... – Alexander Vogt Jun 18 '14 at 16:54
  • Yes I know. While making `call sub(ai(2),3))`, I just want to pass to the subroutine isub the adress or reference of the second element of ai. And I do not want to use assumed shape array in the subroutines because of performance concern (and I cannot use the CONTIGUOUS attribute because I am stuck to f95). But it does not work... – janou195 Jun 18 '14 at 17:19
  • @janou195 There usually are no performance penalties for contiguous sub-arrays... See my updated answer. – Alexander Vogt Jun 18 '14 at 17:28
  • "I'm wondering why call isub(ai(2)) is accepted, though..." - sequence association - see 12.5.2.11 in F2008. Sequence association is incompatible with generic resolution, because generic resolution is based on the rank of the argument and the rank of an actual argument participating in sequence association isn't well defined. – IanH Jun 18 '14 at 21:30
  • @Alexander Vogt Are you totally sure that declaring a as an assumed shape in the subroutine have no performance impact? Puttig asside the question of the temporary, to my understanding, when building a subroutine with an assumed shape array dummy argument, the compiler does not know if the subroutine will be called with a contiguous actual argument or not, and so have to assume that it is not contiguous and disable some optimizations in the subroutine. Or maybe the subroutine is compiled twice: a "contiguous" and a "non-contiguous" versions?? – janou195 Jun 20 '14 at 08:16
  • I think what you are asking here is very compiler-specific. The Fortran Standard does not enforce this. But to my knowledge (and experience) there is no performance penalty. – Alexander Vogt Jun 20 '14 at 09:41