Why is %goto discouraged to use in program ? I ,however, see extensitve use of it in macro program. Are there alternatives for this?
Thanks !
In my early days of FORTRAN, goto was almost all we had to control what part of the programs were executed. Shudder! Then when structured programming came along, gotos fell out of favor. Many people considered them a sign of bad programming. Personally, I never bought into that. I don't use them for most things, but I frequently use them for:
if fatal-error then goto abort.
Specifically, this is how most of my DATA steps end in production macros.
if _error_ then call symput('abort', '1');
run;
%if &syserr > 4 %then %let abort = 1;
%if &abort = 1 %then %goto endit;
I occasionally do things like this:
if recoverable-error then do; do things to recover; goto the top and try again; end;
Personally, I think it is fine to use a goto when it is the right tool for the job.
Here is the one I fould online.
http://www.u.arizona.edu/~rubinson/copyright_violations/Go_To_Considered_Harmful.html
In 20 years of SAS programming I have never used a %goto. It's not that I consciously avoid it, I just never had the need for one. Maybe it's the fact that I started programming with languages that provide strong structuring (Pascal and C), and therefore "see" an algorithm as a construct of such structures, without the need for "escaping".
I still miss fortran sometimes. I largely agree though. GOTO is a tool, and like any tool it can be used and abused. Sometimes GOTO really is the best tool for the job, it can be easily abused to make code practically unreadable, but it can also simplify code substantially in the right cases.
One thing I should add about my use of %goto: I write autocall macros for SAS. Most are large; some are huge. %MktEx is 18,368 lines including the massive comment block up top. It has many procedure and DATA steps. I want it to behave gracefully no matter how silly the input might be. So I check &syserr at every step boundary and have many reasons why I want to skip to the end. I never want hundreds or thousands or even a dozen useless errors appearing in the log. I could write code that conditionally executed the next step only if everything up to that point was OK. It is so much easier and I think cleaner to use the "if disaster then go to abort" approach. I do the same thing when I write SAS procedures. So I write gotos quite often, because I so compulsively check for errors, but in practice most are rarely executed. I can't think off hand of any time I use them as a part of "normal" processing. I would hate to try to write bullet-proof code without them. In contrast, when I write code when I am willing to assume reasonable input, I almost never use them. They are a great tool when they are needed.
Well, just as a thought here, what does the Functional Design Specification for that macro which is 18k lines long look like? I am thinking code like that, may be better being broken up into logical blocks and subdivided out into various objects, linked to higher objects, then to the final top level object. Thus you would effectively have a tree of objects which could be called from the main object via a sort of select mechanism, having conditional logic to only execute the next levels of the tree when conditions are met, something like (and apologies, just did this real quick in Excel):
%goto is the only way to leave a loop or block of code without executing the remaing lines of code in the MACRO language so you'll see it there.
One of the main "complaints" of goto comes from just figuring what code is executed in what order when it comes time to maintain it. Especially if you have goto instructions that go to places earlier in the code. Often goto lines were inserted for one case but then the programmer found out that created another special case in another part of the code, and another. Next thing you know you see things jumping from line 10 to line 450 to line 37 to line 666 to line 10 ...(yes that 10 is intentional and potentially an infinite loop).
Less disciplined or aware programmers could create things that took days to unravel (I think it was sometimes referred to as "job security).
HINT: If you find yourself looking to add a second GOTO in any program stop, breathe, think about what is going on. It may mean that you need to reorder the code, add a variable or possibly consider a structure such as SELECT/WHEN blocks to control the code.
I don't think I've actually used a %GOTO in 10 years or more and I probably average writing one macro a week.
There is no reason to NOT use GOTO statements. Just don't use them to create spaghetti code.
Macros do not have INIT and TERM sections that you might see in more modern programming languages. Because of that it is more important to follow structured programming principles and insure that all programs have one entry point and one exit point. If you don't want to add unmanagable levels of nested %IF/%THEN blocks then strategic use of %GOTO can insure that all conditions that require the macro to stop will still execute the termination steps at the end of the macro.
Personally I find the use of %RETURN statement more objectionable since it could lead to the macro having two or more points of exit.
Thanks all for the great insights. I hope to learn more about it.
SAS Innovate 2025 is scheduled for May 6-9 in Orlando, FL. Sign up to be first to learn about the agenda and registration!
Learn how use the CAT functions in SAS to join values from multiple variables into a single value.
Find more tutorials on the SAS Users YouTube channel.
Ready to level-up your skills? Choose your own adventure.