Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Break from SELECT CASE

Unlike C, Fortran does not need a break in each case. But is there a way to jump out of the select case statement besides goto? (I'd rather choose another way to jump if possible and I cannot use exit in select case statement.)

select case(key)
case("cat")
    if(value > 5) !break!
case("dog")
...
endselect

Here is an more detailed example. Though there are other types of flow control, break will be the best in my opinion

integer, allocatable :: Err(:)
select case(key)
case("cat")
    if(value1 > 5) call PushBack(Err, 1001)
    if(NotANumber(value2)) call PushBack(Err, 1002)
    if(value3 /= "good") call PushBack(Err, 1003)
    if(allocated(Err)) !break!
    .... !some processing
case("dog")
    ....
endselect
if(allocated(Err)) call ShowError(key, Err)

If I put everything in if:

integer, allocatable :: Err(:)
select case(key)
case("cat")
    if(value1 > 5) then            !Here only one of the value1, value2... is checked
        call PushBack(Err, 1001)
    elseif(NotANumber(value2)) then
        call PushBack(Err, 1002)
    elseif(value3 /= "good") then
        call PushBack(Err, 1003)
    else
        .... !some processing
case("dog")
    ....
endselect
if(allocated(Err)) call ShowError(key, Err)

If there are better solutions, please let me know.

like image 581
FortCpp Avatar asked Sep 05 '14 00:09

FortCpp


2 Answers

You have encountered an improvement introduced in Fortran 2008 that is not fully implemented in compilers. In Fortran 2008 exit can be used relating to things other than do loops.

I consider three approaches valid:

case1: select case(key)
case("cat")
  if (value > 5) exit case1
case("dog")
...
end select case1

This is the Fortran 2008 way.

case1: select case(key)
case("cat")
  if (value > 5) goto 1  ! Let's pretend this is an exit: we'll have compiler
                         ! support soon enough, and we can replace with exit
case("dog")
...
end select case1
1 continue

This is fake-Fortran 2008 way. The comment is vital to this approach.

massive_hack: do k=1,1
  select case(key)
    case("cat")
      if (value > 5) exit massive_hack
    case("dog")
      ...
  end select case1
end do massive_hack

This is the Fortran 2003/hating gotos way.

All of these are preferable, to me, to introducing spurious flow-control within cases.


Explanation:

The wording in the Fortran 2003 standard for the exit statement is:

The EXIT statement provides one way of terminating a loop.

...

An EXIT statement belongs to a particular DO construct. If the EXIT statement refers to a DO construct name, it belongs to that DO construct; otherwise, it belongs to the innermost DO construct in which it appears.

whereas Fortran 2008 extends that with:

The EXIT statement provides one way of terminating a loop, or completing execution of another construct.

...

An EXIT statement belongs to a particular construct. If a construct name appears, the EXIT statement belongs to that construct; otherwise, it belongs to the innermost DO construct in which it appears.

The select case construct is one to which the above explicitly applies.

Cursory glances suggest current versions of the Cray, NAG, GCC and IBM compilers support this enhanced behaviour.

like image 105
francescalus Avatar answered Oct 19 '22 09:10

francescalus


Extended comment rather than answer ...

I don't understand what the problem is that @Francescalus has solved for you. Only one of the cases will be executed, the break to the end of the select case construct is the way that Fortran behaves. In your fragment:

select case(key)
case("cat")
    if(value > 5) !break!
case("dog")
...
endselect

only the line if(value > 5) !break! is executed if cat is selected. If your fragment ought to have been

select case(key)
case("cat")
    if(value > 5) then
        break
    else
        long and tedious processing
    end if
case("dog")
...
endselect

well that's just a long-winded way of writing

select case(key)
case("cat")
    if(value <= 5) then
        long and tedious processing
    end if
case("dog")
...
endselect

The break statement (or some syntactic equivalent) is needed in C and its ilk because the default behaviour is to fall through at the end of each case.

It seems to me @Francescalus's massive_hack is an absolutely appropriate use of exit in Fortran 2008, enabling an exit from an enclosing do construct to terminate a computationally-heavy loop over a sequence of elements.

I expect I've missed the point entirely ....

like image 7
High Performance Mark Avatar answered Oct 19 '22 10:10

High Performance Mark