j3-fortran / fortran_proposals

Proposals for the Fortran Standard Committee
178 stars 15 forks source link

Allow a contained procedure to exit the calling procedure #337

Open jacobwilliams opened 2 months ago

jacobwilliams commented 2 months ago

Here's a little thing that I have frequently wanted: some syntax to allow a contained procedure (say in a subroutine) to have a return statement that applies to the calling procedure. This is to replace something like this:

subroutine main()

! do some stuff
if (error) then
  call raise_error()
  return   !<--- have to remember to put this everywhere this routine is called
end if
! some other stuff

contains
  subroutine raise_error()
   ! do some error handling stuff
 end subroutine raise_error
end subroutine main

with:

subroutine main()

! do some stuff
if (error) call raise_error()   <---- calling this returns from main
! some other stuff

contains
  subroutine raise_error()
   ! do some error handling stuff
   return main  ! <- some kind of new syntax
 end subroutine raise_error
end subroutine main
ivan-pi commented 2 months ago

I have also wanted this for the same reason.

The best alternative I can think of is putting the body in a block and then branching out:

subroutine main()

try: block
   ! some stuff
   if (error) exit try
   ! some other stuff

   return     !<--- have to remember to put this here
end block try

call raise_error()
contains
   ! ...
end subroutine

The other way would be goto but I hope we all agree this isn't pretty:

subroutine main()
! some stuff
if (error) goto 999
! some other stuff

return   !<--- have to remember to put this here

999 call raise_error()

contains
   ! ...
end subroutine

The numeric labels feel anachronistic (even C has named labels!) plus they completely mess up formatting in free-form.

I've been meaning to submit a paper to expand the rules for goto to allow named labels:

subroutine main()
! do stuff
if (error) goto error_handling
! do other stuff

return   !<--- still have to remember to put this here

error_handling: block
    call raise_error()
end block error_handling

contains
   ! ...
end subroutine

This would also be useful for I/O procedures which allow jumping to numeric label upon error, so it can be pursued independently of what you are proposing here.

klausler commented 2 months ago
subroutine outer
  call other(inner)
 contains
  subroutine inner
    return outer
  end
end

subroutine other(e)
  call e
end
certik commented 2 months ago

@klausler I can't even wrap my head around this example, let me try:

subroutine outer
  call other(inner)
 contains
  subroutine inner
    return outer
  end
end

subroutine other(e)
  call e
end

Let's inline other:

subroutine outer
  call inner
 contains
  subroutine inner
    return outer
  end
end

Ok, so this should just return from outer it seems.

Is your point how to do this when other can be defined in another module, or linked later?

ivan-pi commented 2 months ago

Couldn't one just add a rule that a procedure returning from outer cannot be passed as a procedure argument or associated to a procedure pointer, but only used via a direct call in the applicable scope?

certik commented 2 months ago

@ivan-pi it's a useful pattern that I use quite often to pass the inner procedure as a callback into some solver. It allows me to "pass the context" that way.

ivan-pi commented 2 months ago

That is useful indeed. I meant only for the case where the inner procedure would return to somewhere else than the place where it was called itself.

jacobwilliams commented 2 months ago

I have no idea what these outer/inner examples are trying to show here. I think it's too late in the day on Friday or something.

jacobwilliams commented 2 months ago

@ivan-pi Yes the block thing is as good as we have now I think. But it would be annoying to have to put a block and indent every single subroutine we write.

jacobwilliams commented 2 months ago

In reality, what we really need is some kind of actual exception handling feature in Fortran. But I fear we will never get that.

klausler commented 2 months ago

In reality, what we really need is some kind of actual exception handling feature in Fortran. But I fear we will never get that.

I know that they are disapproved, and work only for subroutines, but alternate returns are somewhat adjacent to a decent procedure-scoped exception mechanism that exists today. Perhaps they could be rehabilitated and lightly extended (to work with functions, and to permit forwarding of inbound alternate return arguments to outgoing calls).

jwmwalrus commented 2 days ago

Hi.

(This post is a bit self-promoting, but...)

A while ago I proposed an exception handing mechanism, and today I posted an updated version ---which I think covers the issue here.