Sorry, REXX SIGNAL does not suck; you just don't know how to use it.  It
only trashes the current DO...END structure.  It works just fine if you
code something like:

DO Outerloop = 1 to n
  Call processes_item
End

Process_item:
Signal ...
Return

Any errors encountered in 'Process_item' will not stop Outerloop.

John


-----Original Message-----
From: IBM Mainframe Assembler List
[mailto:ASSEMBLER-LIST@LISTSERV.UGA.EDU] On Behalf Of Paul Gilmartin
Sent: Friday, February 04, 2011 10:09 AM
To: ASSEMBLER-LIST@LISTSERV.UGA.EDU
Subject: Re: Best (or any) practices to rewrite "spaghetti"

On Feb 3, 2011, at 12:57, Edward Jaffe wrote:

> On 2/3/2011 10:41 AM, Johanson, Adam wrote:
>>         Then, I told myself that the whole point of the exercise was
to make the code more readable, so a branch to a return-to-caller label
every now and then didn't really defeat the purpose and actually _did_
help things. IMHO, rather than seeing a big nested IF statement and
chasing down the end point just to figure out that you're gonna return
to the caller is a bit more involved than realizing, "Oh, I'm just
getting out of Dodge."
>
> Yup. You can find analogs in other languages. For example SIGNAL and
EXIT in
> REXX. Programs can become unnecessarily complex if you require every
condition
> to be surfaced back up through a deeply-nested logic hierarchy.
>
Rexx SIGNAL sucks.  One one hand, it trashes the DO...END structure;
OTOH
it leaves the subroutine return stack hanging (a naive colleague once
authored a Rexx program that used SIGNAL to "get out of Dodge".  He
tested
it, apparently successfully.  It crashed on a large input data set when
the stack overflowed.  PITA to refactor.)  Absence of a construct to
exit a nest of procedures impels Rexx programmers to eschew subroutines
in contexts where they'd otherwise be preferable.

I'd cherish an extension to support "LEAVE control-variable" where
control-variable belongs to a loop in an outer procedure exposed in
the inner procedure containing the LEAVE.

But Rexx does support LEAVE and ITERATE for outer DOs.  I habitually
code:

    do OuterLoop = 1 for 1
        ...
        do
            ...
            do
                ...
                leave OuterLoop
                ...
            end
            ...
        end
        ...
    end OuterLoop

> Depending on your program design, an "signal/exit jump from anywhere"
can be
> problematic when using a stack for (at least) saving/restoring
registers. If you
> "signal/exit" with the stack pushed several levels deep, your current
registers
> might not be appropriate for the "signal/exit" routine and, if the
stack is
> needed for any processing after that, you'll need a way to unwind the
stack to
> the appropriate level or else things might go horribly wrong--for
example when
> the "signal/exit" routine itself tries to return to the original
caller.
>
> The easiest way to avoid this is to never branch to a "signal/exit"
label from
> an inner routine. Or put another way, each stack level has its own
"signal/exit"
> routine.
>
> Another way we've handled the "signal/exit jump from anywhere" is to
save the
> appropriate stack control and registers in some easily addressable
non-stack
> storage from which they are loaded/copied as one of the very first
things the
> "signal/exit" routine does.
>
> FWIW, when writing code from scratch it is often possible to avoid
"signal/exit"
> branches entirely by enclosing the logic within two nested simple DOs
as shown.
> We have used this technique quite effectively in some very large and
complex
> programs. (This is only an example. Many other variants of this
approach are
> possible.)
>
> | DO LABEL=MainLine            Do for MainLine routine
> |
> |   ************************************
> |   * Process MainLine Logic Here      *
> |   ************************************
> |   DO LABEL=MainLineLogic       Do for MainLine logic
> |     .
> |     .(some deeply nested code here discovers an error)
> |     LHI   R15,ErrorCode1         Load error code
> |     LEAVE MainLineLogic          Go perform error processing
> |     .
> |     .(another error is discovered)
> |     LHI   R15,ErrorCode2         Load error code
> |     LEAVE MainLineLogic          Go perform error processing
> |     .
> |     .(this can be a very large and complex routine)
> |     .
> |     XR    R15,R15                Set return code = 0
> |     LEAVE MainLine               Exit the routine
> |   ENDDO , MainLineLogic        EndDo for MainLine error trap
> |
> |   ************************************
> |   * Process MainLine Errors Here     *
> |   ************************************
> |   SELECT CHI,R15,EQ            Select error code
> |   WHEN ErrorCode1              ErrorCode1
> |     (whatever)                   Issue msg, set retcode/rsn, etc.
> |   WHEN ErrorCode2              ErrorCode2
> |     (whatever)                   Issue msg, set retcode/rsn, etc.
> |   OTHRWISE ,                   Unknown Error Code
> |     J     *+2                    Logic error. Force abend here.
> |   ENDSEL ,                     EndSel error code
> | ENDDO , MainLine             EndDo for MainLine routine
>
>
>>         And you've probably come across it in the SHARE presentations
that you've seen, but if you're going to do this, download Ed Jaffe's
FLOWASM exit. It makes life easier.
>
> I'm glad you found it useful. 8-)
>
> --
> Edward E Jaffe
> Phoenix Software International, Inc
> 831 Parkview Drive North
> El Segundo, CA 90245
> 310-338-0400 x318
> edja...@phoenixsoftware.com
> http://www.phoenixsoftware.com/

Reply via email to