The issue of macro variable scope is a tricky one, and worth working through.
You asked for a brief explanation why the %LOCAL statement should almost always be used to define macro variables as %local to a macro. I would say:
Suppose I'm a macro user. And in my SAS session I have some global macro variables that I created for my own work.
I call a macro, %storms() .
I don't expect the macro storms to change the value of any of my global macro variables, they belong to me, not the macro.
If the author of the the macro %storms() did not use the %local statement to define macro variables as %local, then the macro storms might change the value of my global macro variables. And as a user of the macro, there is no way for me to prevent that from happening.
The issue is not necessarily whether the macro itself works, it's instead a side-effect problem of the macro changing something that doesn't belong to the macro.
Consider this macro without a local statement, which just writes the items in a list to the log:
%macro withoutlocal(list);
%let count=%sysfunc(countw(&list));
%do i=1 %to &count;
%let yr=%scan(&list,&i);
%put &=yr ;
%end;
%put _user_ ;
%mend withoutlocal;
If I call that macro:
%withoutlocal(A B C)
it works. And the macro variables COUNT, I, and YR will all be created as local macro variables. I added a %PUT _USER_ statement to show this:
197 %withoutlocal(A B C)
YR=A
YR=B
YR=C
WITHOUTLOCAL COUNT 3
WITHOUTLOCAL I 4
WITHOUTLOCAL LIST A B C
WITHOUTLOCAL YR C
However, suppose I create a global macro variable named count, which I want to use in my program for some purpose unrelated to the macro. And then suppose I call the macro.
%let count=100;
%withoutlocal(A B C)
%put &=count;
Now the log shows that instead of creating a local macro variable named COUNT, the macro used *my* global macro variable count. The macro "worked" in terms of returning the items of the list. But after the macro has run, my macro variable COUNT has the wrong value, because the macro wrote the value 3 to my macro variable, instead of creating its own macro variable:
198 %let count=100;
199 %withoutlocal(A B C)
YR=A
YR=B
YR=C
WITHOUTLOCAL I 4
WITHOUTLOCAL LIST A B C
WITHOUTLOCAL YR C
GLOBAL COUNT 3
200 %put &=count;
COUNT=3
As a user of a macro, I can't prevent the macro from accidentally changing my macro variables, if I happen to have macro variables that have the same name as macro variables used in the macro. I rely on the macro author to be conscientious enough to declare all the macro variables to be %local, to prevent "collisions" with my macro variables.
The general guideline for writing macro is when you create a macro variable, always use the %LOCAL statement to create them as local to the macro, unless you have a really really good reason not to do so. To protect your users (and yourself) from collisions.
... View more