02-22-2018 09:59 AM
%let mv = shoes; %macro product (mv = bicycles); %let mv = clothes; %mend; %product(mv = tents) %put mv is &mv;
How is the answer " mv is shoes" processed? I see somebody says when the local macros finished execution, they disappear, so the answer will be the global macro "shoes". If this is true, why the next problem does not choose the global macro ("cat") as the answer?
Another problem: Why the answer is "a is dog" rather than cat (I think "cat" is global macro)?
%let a=cat; %macro animal; %let a=dog; %mend; %animal %put a is &a;
02-22-2018 10:10 AM
A macro parameter [specified in %macro ()] is not treated the same way as a %let statement inside the macro. The %let statement uses the already existing macro name in its already defined scope. Google "scope of sas macro variables" for more info.
02-22-2018 10:30 AM
Agreeing with @WarrenKuhfeld and adding some explanation ...
%LET does not automatically create a new macro variable. It first looks to see if it can find an existing macro variable with the right name. If the search is successful, that's the variable %LET uses.
So the top program looks first in the local symbol table, finds &MV there (with a value of bicycles), and changes its value to clothes. The macro ends, the local symbol table disappears, and the %PUT statement uses the only &MV it can find, the one in the global symbol table.
The bottom program forces %LET to look for an existing macro variable (&A). It finds nothing in the local symbol table, so it searches the global symbol table. Finding &A (with a value of cat), it changes the value to dog. There is never a local macro variable named &A. Both %LET and %PUT use the global macro variable &A.
02-22-2018 10:38 AM
When working with macro variables and scoping, I like to visualize it like each variable within the macro program is a piece of paper that you're adding to a stack. We start off and put the mv (shoes) piece of paper onto the stack, which is just the one paper right now. We can see that paper and take it away or update it whenever we want. But when we move into the %product macro, we have to add a new piece of paper. This is the positional parameter mv. This is NOT the same mv from before; this is a local macro variable. It needs a new piece of paper. So now we have a piece of paper called mv (tents). After adding that paper, we see it's time to update mv to clothes. But it's hard to get to the original macro variable because that paper is UNDER the new piece of paper! Since we can't get to that variable without moving our papers around, we instead update our top sheet (the local mv) When we see %mend, that means all the local variables need to be removed. We take off and throw away the mv (clothes) paper. Now the only variable left is the original macro variable mv (shoes). That's what prints when we run the program.
Why is this different than the dog and cat example?
We start off easy again: a single piece of paper called a (cat). We go inside the macro %animal and we IMMEDIATELY see a reassignment to that macro variable a. Since it's already on the top of the stack, we're able to make changes to that paper without moving anything else around or creating a new, local version of a. We scratch out a (cat) and write a (dog). The macro is able to complete with only a single piece of paper running around, so the values change as you would expect, given their names.
Hope this helps if you're struggling with the visuals!
02-23-2018 12:42 PM
Thank you very much for your picturesque explanation! I think it still needs me to put some effort to understand completely! But your answer really helps a lot! Thank you a lot!
02-23-2018 03:27 PM - edited 02-23-2018 03:29 PM
Using the command
Can really help make the difference clearer.
So here is the result if we run the first macro:
1 %let mv = shoes; 2 %macro product (mv = bicycles); 3 %put _user_; 4 %let mv = clothes; 5 %put _user_; 6 %mend; 7 %product(mv = tents) PRODUCT MV tents GLOBAL MV shoes PRODUCT MV clothes GLOBAL MV shoes 8 %put mv is &mv; mv is shoes
So you can see that when %PRODUCT starts there are two macro variables name MV. One is GLOBAL symbol table and one in the PRODUCT symbol table. It is this most local version that is updated by the %LET statement.
Now if you run the second example you can see that there never is a local macro variable named A.
9 %let a=cat; 10 %macro animal; 11 %put _user_; 12 %let a=dog; 13 %put _user_; 14 %mend; 15 %animal GLOBAL A cat GLOBAL MV shoes GLOBAL A dog GLOBAL MV shoes 16 %put a is &a; a is dog
02-25-2018 04:52 PM
Thank you very much for answering my question! Your answer is really helpful although I already use this method (options symbolgen mlogic) to comprehend this program.
03-02-2018 08:08 PM
03-02-2018 08:12 PM - edited 03-02-2018 08:13 PM
In the second program, &A is created before the macro begins.
When the macro executes, it finds there is an existing &A (in the global table) and therefore uses the existing &A, changing its value from cat to dog.
03-02-2018 09:16 PM
Saw this post today and I wonder why dog is a global variable in the second program. It’s little confusing to me that variable created inside macro is a global variable. Can anyone give me some advices? Thanks.
There is no macro variable named DOG in any of the programs.
In the second program the macro variable is named A. It is created outside of any macro environment and so it is created in the global symbol table. When the macro runs it sets the value of A to dog. It does not create a macro variable in the local symbol table since there was already a macro variable named A that the %let statement could use.
03-02-2018 08:39 PM
03-02-2018 09:17 PM - edited 03-02-2018 09:27 PM
If I’m following this logic, that means &A is created in the global symbol table before the macro begins, which is cat. But then when macro executes, it finds another global variable for &A which is dog, so macro processor replace cat by dog?
"&A" is not created anywhere. The syntax &A is a reference to the value of a macro variable named A.
The macro variable A was created in the global symbol table by the %LET statement that assigned it a value of cat.
When the macro runs the %LET statement in the macro assigns a new value of dog to the macro variable named A. Because nothing ever created a local macro variable named A the value is assigned to the existing macro variable A, the one in the global symbol table.
03-02-2018 09:40 PM