BookmarkSubscribeRSS Feed
🔒 This topic is solved and locked. Need further help from the community? Please sign in and ask a new question.
Reeza
Super User

@SAS_inquisitive wrote:

Hello:

 

I am looking for an example where inner macro definition gets the input from outer macro definition.  Is this type of construction possible?

 


Possible does not mean you should. And you really really shouldn't do this. Please never do this. Ever.

Tom
Super User Tom
Super User

Macros are NOT nested, the list of macro names is a simple list, not a heirarchy.  Nesting one macro's definition inside of another macro will not change that fact.

 

Macro EXECUTION can be nested.

 

If an outer macro calls an inner macro then the scope of the other macro is available to the running inner macro.  That means that macro variables defined as LOCAL in the outer macro exist and are visible to the inner macro to read and modify.  The exception is when the inner macro has its own LOCAL macro variable with the same name. The existence of that local macro variable will hide any macro variable(s) with the same name that exist in any currently running scope (including the GLOBAL scope).

 

If you nest the macro definitions the only impact will be that every time you call the outer macro then the inner macro will be re-compiled (needlessly).

 

I cannot think of any way that you could change the definition of that inner macro by placing the definition inside the definition of the outer macro.  The only thing that I can think of that might have made it possible was a bug that impacted how macro variable references used in default values for parameters were handled.  But that was fixed.  Apparently the bug was introduced when they switched from PL/I to C compilers (early 80s?) and not fixed until just a few years ago.  Shows much that type of functionality was ever used/needed.

SAS_inquisitive
Lapis Lazuli | Level 10

@Tom. I tested it out here. Thanks !

%macro outer;
	%local a;
	%let a = 10;

	%macro inner;
		%let b = 10;
		%let total = %eval(&a + &b);
		%put &total;
	%mend inner;
	%inner;
%mend outer;
%outer;
Tom
Super User Tom
Super User

@SAS_inquisitive wrote:

@Tom. I tested it out here. Thanks !

%macro outer;
	%local a;
	%let a = 10;

	%macro inner;
		%let b = 10;
		%let total = %eval(&a + &b);
		%put &total;
	%mend inner;
	%inner;
%mend outer;
%outer;

You will get the same result without nesting the DEFINITIONS.

%macro inner;
  %let b = 10;
  %let total = %eval(&a + &b);
  %put &total;
%mend inner;
%macro outer;
  %local a;
  %let a = 10;
  %inner;
%mend outer;

%outer;
SAS_inquisitive
Lapis Lazuli | Level 10

@Tom. You are creating local macro variable &a in outer macro (so this will be available for outer only, right ?). How does this become available to inner macro? It is because macro definitions are stored in global symbol tables  as @Kurt_Bremser said?

Tom
Super User Tom
Super User

@SAS_inquisitive wrote:

@Tom. You are creating local macro variable &a in outer macro (so this will be available for outer only, right ?). How does this become available to inner macro? It is because macro definitions are stored in global symbol tables  as @Kurt_Bremser said?


No. You don't seem to understand how macro variable scoping works.  Someone recently posted a great analogy. 

 

Think of each macro variable as a piece of paper that you can write information on (and read it back).  You have a big table where each location on the table is reserved for a single possible macro variable name.  When no macros are RUNNING then only the pieces of paper that represent global macro variables are on the table.  When you start a macro running and it defines a local macro variable then a new piece of paper is put on the table. If the name matches an existing macro variable then the new piece of paper is placed on top of the existing paper and hides it.   When a macro stops running then all of the pieces of paper that represent that macros local macro variables are removed, which is easy to do since the papers that represent the local macro variables for the current macro are always going to be on the top.

 

At any point in time you can only access the pieces of paper that are the top.

 

So when the INNER is running the macro variable A defined in OUTER is visible. You haven't created a local macro variable that would hide it and the OUTER macro is still running (it is waiting for the call to INNER to end).  So you can see the piece of paper. You can also write on it.  So if INNER modifies the macro variable A then when INNER ends and OUTER continues running the value of A has been changed.

Kurt_Bremser
Super User

@SAS_inquisitive wrote:

@Tom. You are creating local macro variable &a in outer macro (so this will be available for outer only, right ?). How does this become available to inner macro? It is because macro definitions are stored in global symbol tables  as @Kurt_Bremser said?


Try it. Create some macros that define macro variables locally or simply use them without %local, and use %put statements, then call these macros one within the other. Little exercises like that often provide a great learning experience.

Kurt_Bremser
Super User

To keep my sanity, I have implemented this strategy for using macro variables in a macro:

There are these four types of variables:

  • macro variables that are actually parameters; these are by definition local
  • existing global macro variables used for overall control of the code; these must not be changed inside the macro, have a fixed definition and are known by all developers (eg type of an external host from which files are read - UNIX/Mainframe/Windows); they are usually set at program start in autoexec or similar
  • newly created variables for later global use, therefore appearing in a %global statement
  • local macro variables, named in a %local statement; this encompasses all variables not in one of the above categories. %local prevents side-effects

Other types of use are not allowed, to prevent unwanted side-effects.

 

There may be certain exceptions, but these need to be clearly described in comments when made.

 

 

In light of this, the way you use &a in the "inner" macro is a violation of these principles and MUST NOT HAPPEN. Pass it as a parameter.

 

And as others have said, all %macro definitions are stored in the global symbol table, so trying to "nest" macro definitions makes no sense. Nesting macro calls is of course possible and requires caution and planning. You can even call macros recursively:

%macro test(x);
%put X=&x;
%if &x < 5
%then %do;
  %let x = %eval(&x+1);
  %test(&x);
%end;
%mend;

%test(1)

sas-innovate-2024.png

Available on demand!

Missed SAS Innovate Las Vegas? Watch all the action for free! View the keynotes, general sessions and 22 breakouts on demand.

 

Register now!

How to Concatenate Values

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.

Click image to register for webinarClick image to register for webinar

Classroom Training Available!

Select SAS Training centers are offering in-person courses. View upcoming courses for:

View all other training opportunities.

Discussion stats
  • 22 replies
  • 3106 views
  • 8 likes
  • 7 in conversation