3

Suppose I have a subroutine:

subroutine foo(x, Nx)
    implicit none
    integer, intent(IN) :: x
    integer, intent(IN) :: Nx

    select case(x)
        case (1)
            write(*,*) "Minimum value"
        case (Nx)
            write(*,*) "Maximum value"
        case default
            write(*,*) "Somewhere in-between"
    end select
end subroutine foo

Suppose my driver looks like this:

program main
    implicit none

    interface
        subroutine foo(x,Nx)
            integer, intent(IN)  :: x
            integer, intent(IN)  :: Nx
        end subroutine foo
    end interface

    integer, parameter :: Nx = 100
    integer :: x

    call foo(20, Nx)

end program main

The above program will not compile because in the subroutine, case (Nx) is invalid. Specifically, ifort 16 gives the following error:

error #6601: In a CASE statement, the case-value must be a constant expression.

In other words, even though Nx is effectively declared as a subroutine constant via intent(IN), it needs to be either a literal constant or parameter of type integer.

Are there any ways to make the case statement accept Nx as the constant parameter we know it to be? Is there some way to declare Nx to be a passed-in parameter?

I realize that in this simple, short example, an if-then-elseif-else-end block would suffice, but then I wouldn't know the answer to this question. :-)

jvriesem
  • 1,859
  • 3
  • 18
  • 40
  • 1
    FYI you're missing an end quote after `"Maximum value`. And possibly a `::` in `integer, parameter Nx`. – Andras Deak -- Слава Україні Sep 13 '15 at 19:16
  • 1
    Could you define a module that would contain your parameter along with the subroutine, and if so, would that help?:) – Andras Deak -- Слава Україні Sep 13 '15 at 19:21
  • By the way, you say "In other words, even though Nx is effectively declared as a subroutine constant via `intent(IN)`...". I think the problem is that fortran needs to know the `case` values *during compile-time*, so being a subroutine constant is not enough. Otherwise I don't see why it would hurt the compiler to find out the values on-the-fly, without having to prescribe any constant attribute. – Andras Deak -- Слава Україні Sep 13 '15 at 19:32
  • @AndrasDeak: Other languages don't require switch/select/case constructs to have compile-time constants (they often aren't!). I acknowledge language specifications, but I think this is something that is more of a bug than a feature. (But what do I know?! :-) ) I think the module idea might work (Personal ToDo: test this), though it wouldn't be elegant for this purpose. – jvriesem Sep 16 '15 at 03:30
  • The point is that the case construct can typically be implemented as a jump-table and not as if-else branches. C has the same property. – Vladimir F Героям слава Sep 16 '15 at 08:59

2 Answers2

5

Just use an if statement. A subroutine argument (which you call parameter) is certainly not a parameter (named constant). The intent(in) doesn't make it effectively a parameter, it is just a promise you will not change it, but there are ways to circumvent that. The case statement needs a compile-time constant.

3

You ask whether there is a way to "accept Nx as the constant parameter we know it to be?". We don't know that Nx forms a constant expression, and we indeed know that it doesn't.

The only way for Nx to be a constant expression is for Nx to be a named constant. Being a named constant is incompatible with being a dummy argument, even one which is argument associated, with intent(in) or no intent attribute, with a named constant.

Conceptually, the subroutine foo is an external procedure as far as the main program is concerned (there's an interface block). This means that one would expect it to be compiled as a stand-alone thing, being linked in at that later stage. It should be valid regardless of its ultimate use. [That said, even when it isn't an external procedure the first part still holds as far as the language specification goes.]

Naturally, there are other ways to have Nx a named constant in the subroutine if you don't want to rewrite this using an if construct.

francescalus
  • 30,576
  • 16
  • 61
  • 96