Why the following implicit array assignment works?

Can anyone explain why the example below works?
In the subroutine subr, variable s is scalar, and integer variables, j and k are not initialized, but somehow, the assignment to s(i,k) is applied to all possible values of j and k as if implied do exists, and the variable s is treated as if an array variable.
This example can be compiled and run correctly with GNU Fortran compiler (gfortran), NVHPC Fortran compiler (nvfortran), and Intel Fortran compiler (ifort), but I don’t understand why this code works.
(All tested compilers fail if the PRINT statement before the s(i,k) assignment statement is enabled, which may mean that the s(i,k) assignment statement works only if it is the first executable statement in the subroutine.)

      PROGRAM magicAssignment
      integer, parameter :: dp = selected_real_kind(15)
      integer, parameter ::  mxpart = 14
      integer:: i,m 
      real(dp)::p_p(mxpart,4), val 
      val = 1._dp
      DO i=1, 4
      DO m=1, mxpart
        p_p(m,i) = val 
        val = val + 1._dp
      END DO
      END DO
      CALL subr(p_p)

      CONTAINS
      SUBROUTINE subr(p)
      implicit none
      real(dp),parameter:: two=2._dp
      integer:: j,k,error
      real(dp):: p(mxpart,4),s,sCal
!     "Error: Unclassifiable statement" occurs for line 24 if the print
!     statement below is enabled
!      PRINT *,'start computation'
      s(j,k)=two*(p(j,4)*p(k,4)-p(j,1)*p(k,1)
     &           -p(j,2)*p(k,2)-p(j,3)*p(k,3))
      error = 0 
      DO k=1, mxpart
      DO j=1, mxpart
      sCal=two*(p(j,4)*p(k,4)-p(j,1)*p(k,1)
     &           -p(j,2)*p(k,2)-p(j,3)*p(k,3))
      IF ( s(j,k) .NE. sCal ) THEN
      PRINT *, 's(', j, ',', k, ') differs from the calculated value(',
     &sCal,')'
      error = error + 1 
      END IF
      END DO
      END DO
      IF ( error .EQ. 0 ) THEN
      PRINT *, '==> No error occurred!'
      END IF
      END SUBROUTINE subr    
      END PROGRAM magicAssignment    

This is not an assignment but a statement function.

Statement functions go into the specification part of the subroutine. Executable statements like print go into the executable part (the body of the procedure) which is below the specification part.

2 Likes

That solves my mystery.
I’m new to Fortran and thus didn’t know about the statement function.
Thanks a lot!

Normally, one would replace statement functions in a legacy code with a contained function in a modern fortran code. Unfortunately, that cannot be done in this particular case because the subroutine is already itself a contained procedure, and fortran allows only limited nesting levels. An alternative is to replace the statement function with a contained function at the same level as the subroutine. This case is simple enough to do that, but you would need to add the p(:,:) dummy argument array as an additional argument which is not in the original statement function, or reference the actual argument array p_p(:,:) directly from the main program.