BookmarkSubscribeRSS Feed
🔒 This topic is solved and locked. Need further help from the community? Please sign in and ask a new question.
SAS_inquisitive
Lapis Lazuli | Level 10

Hello:

 

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

 


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

	%macro inner;
		
		%if &a = 10 %then 
			%do;

		   .........

			%end;

	%mend inner;

%mend outer;

1 ACCEPTED SOLUTION

Accepted Solutions
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.

View solution in original post

22 REPLIES 22
Astounding
PROC Star

Macros can pass information to one another without nesting their definitions  As a result, it is almost never good practice to nest macro definitions.

 

"Almost never" allows for this possibility.  Should executing the %OUTER macro change the definition of the %INNER macro?  It's not a question of whether information can be passed.  That can always happen whether the definitions are nested or not.  It's a question of whether running %OUTER should change the meaning of %INNER.  That almost never happens.

 

 

SAS_inquisitive
Lapis Lazuli | Level 10

@Astounding. You got my point. I did not frame the question correctly. I meant to see how outer macro passes the information to the inner macro (not necessarily changing the meaning of inner macro).

 

Here is seemingly independent inner and outer macros. I want to see the correlation between them.


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

	%macro inner;
		%global b;
		%let b = 20;
	%mend inner;

	%inner;
%mend;

%outer;
%put &a &b;
Astounding
PROC Star

It's easy enough to inspect the result.  The main point that I (and pretty much all) posters are making is that this gives you the same result:

 

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

	%inner;
%mend;
%macro inner; 
%global b;
%let b = 20;
%mend inner; %outer; %put &a &b;

 

There is no need to nest the definitions. 

gamotte
Rhodochrosite | Level 12

Hello,

 

I use macro nesting to create libraries of macro functions.

 

For instance I have a file my_lib.sas containing

 

%macro my_lib;

  %macro mac1(x);
    ...
  %mend;

  %macro mac2(y,z);
    ...
  %mend;

...

%mend my_lib;

Note that the file name (w.o. extension) has to be the same as the main macro name. That allows,

in an external program, to get access to a family of macros with a simple macro call

 

%my_lib

 

%mac1(10)

 

Do you consider it bad practice and if so, what would be the drawback ?

Astounding
PROC Star

Here are some factors to consider.  

 

Have you set up the SASAUTOS option to identify where %MY_LIB is stored?  If you have, the other macros could also be made available without nesting by storing them in mac1.sas and mac2.sas.  (If you haven't done this, SASAUTOS is a good tool to examine.)

 

Nesting the macro definitions gives you long files, making it more difficult to decipher the code.

 

Would %MAC1 and %MAC2 be valuable anywhere else, outside of %MY_LIB?  

 

If you need to locate where %MAC1 and %MAC2 are defined, wouldn't that be easier if there are files named mac1.sas and mac2.sas?

 

 

Do any other macros (other than %MY_LIB) imbed definitions of "convenient names" such as %MAC1 and %MAC2?  When you see %MAC1 or %MAC2 being used, do you know which version is being used?

 

Even if all these questions are easy for you to answer, would they be easy for someone else to answer as well?

Tom
Super User Tom
Super User

@gamotte wrote:

Hello,

 

I use macro nesting to create libraries of macro functions.

 

For instance I have a file my_lib.sas containing

 

%macro my_lib;

  %macro mac1(x);
    ...
  %mend;

  %macro mac2(y,z);
    ...
  %mend;

...

%mend my_lib;

Note that the file name (w.o. extension) has to be the same as the main macro name. That allows,

in an external program, to get access to a family of macros with a simple macro call

 

%my_lib

 

%mac1(10)

 

Do you consider it bad practice and if so, what would be the drawback ?


How does that help? You get the same effect if you just store all three definitions in the same source file without nesting them. When you %INCLUDE the file then all three are compiled.  And if you are using autocall macros then you could store all three definitions in the file named 'my_lib.sas' (without nesting them) and they will be defined the first time you call '%my_lib'.  SAS actually does this sometimes in the autocall library they provide. 

 

I still don't like having multiple macro definitions in the same file.  What is to prevent someone from creating a different version of %MAC1 and storing it in another file?  Then you have a name conflict.  If you store all of your macro definitions in individual files (in the same directory) then the operating system will prevent name collisions.

 

gamotte
Rhodochrosite | Level 12

Thanks @Astounding and @Tom for your valuable input.

 

The idea of grouping several macros in the same file is that they concern a common subject.

We have a constraint that the directory structure that contains our programs is imposed by a  norm

and we can not create sub directories to e.g. group macros by themes. As a result we have a small number

of directories each containing many programs, so reducing the number of programs is a desirable goal.

Those directories have indeed been declared in the SASAUTOS.

 

I understand the concern about macro names conflicts though it never occurred until now.

We have a precise naming scheme that should avoid this kind of problems to occur

but it is a good argument anyway.

 

The use of a macro call instead of an include is just personal taste.

Tom
Super User Tom
Super User

@gamotte wrote:

Thanks @Astounding and @Tom for your valuable input.

 

The idea of grouping several macros in the same file is that they concern a common subject.

We have a constraint that the directory structure that contains our programs is imposed by a  norm

and we can not create sub directories to e.g. group macros by themes. As a result we have a small number

of directories each containing many programs, so reducing the number of programs is a desirable goal.

Those directories have indeed been declared in the SASAUTOS.

 

I understand the concern about macro names conflicts though it never occurred until now.

We have a precise naming scheme that should avoid this kind of problems to occur

but it is a good argument anyway.

 

The use of a macro call instead of an include is just personal taste.


In past we have imposed naming conventions that make it clear if a macro is just a helper macro for a main macro. For example by prefixing the name of the main macro.  So in your example you would have macros names %MYMAC, %MYMAC_MAC1, %MYMAC_MAC2 and the source could would be in files mymac.sas, mymac_mac1.sas, and mymac_mac2.sas

gamotte
Rhodochrosite | Level 12

@Tom wrote:


 

 And if you are using autocall macros then you could store all three definitions in the file named 'my_lib.sas' (without nesting them) and they will be defined the first time you call '%my_lib'. 

 



I have to check that because i think I already tried to do that and the compiler complained that the file contained no macro with the same name.

Quentin
Super User

@gamotte wrote:

@Tom wrote:


 

 And if you are using autocall macros then you could store all three definitions in the file named 'my_lib.sas' (without nesting them) and they will be defined the first time you call '%my_lib'. 

 



I have to check that because i think I already tried to do that and the compiler complained that the file contained no macro with the same name.


 

Definitely works as Tom described.  There should be one macro in the file where the macro name is the name of the file.  Other helper macros can be defined in the same file after that.  Even non-macro code can come after that and will be executed when the macro compiles.  Basically with an autocall library, SAS %includes the file with the macro definition the first time you call the macro.  There are risks of collisions as described.

BASUG is hosting free webinars Next up: Jane Eslinger presenting PROC REPORT and the ODS EXCEL destination on Mar 27 at noon ET. Register now at the Boston Area SAS Users Group event page: https://www.basug.org/events.
Tom
Super User Tom
Super User

@gamotte wrote:

@Tom wrote:


 

 And if you are using autocall macros then you could store all three definitions in the file named 'my_lib.sas' (without nesting them) and they will be defined the first time you call '%my_lib'. 

 



I have to check that because i think I already tried to do that and the compiler complained that the file contained no macro with the same name.


It definitely works. The autocall process will hunt for the filename corresponding to the unknown macro's name and sources the files contents and then proceeds to call the macro.  The error message you mentioned happens if the macro doesn't get defined. So if you saved your example into mac1.sas instead of my_lib.sas.  In that case just including the source wouldn't define mac1 since its definition was hidden inside of the definition of my_lib.

gamotte
Rhodochrosite | Level 12

Sorry, I'm a bit slow.

 

If I, for instance, define a library for handling a users database, with three

macros : %user_add, %user_del, %user_update. I can define the three macros in a

file user_management.sas. AUTOCALL would not work because there is no macro

%user_management.

 

If I decide to rename my file user_add.sas, AUTOCALL would work but i would have to

add a user prior to any other action which may be not what I want.

 

I could create an empty macro %user_management or ... use a nesting macro.

The empty macro just seemed a bit strange to me hence the choice of nesting.

 

Anyway, I am not advocating any solution over another. I perfectly understand the recommandation

of one macro per sas program. Grouping several macros in teh same program is just the workaround we

found to organize our macros without the possibility of acting on the directory structure.

Tom
Super User Tom
Super User

@gamotte wrote:

Sorry, I'm a bit slow.

 

If I, for instance, define a library for handling a users database, with three

macros : %user_add, %user_del, %user_update. I can define the three macros in a

file user_management.sas. AUTOCALL would not work because there is no macro

%user_management.

 

If I decide to rename my file user_add.sas, AUTOCALL would work but i would have to

add a user prior to any other action which may be not what I want.

 

I could create an empty macro %user_management or ... use a nesting macro.

The empty macro just seemed a bit strange to me hence the choice of nesting.

 

Anyway, I am not advocating any solution over another. I perfectly understand the recommandation

of one macro per sas program. Grouping several macros in teh same program is just the workaround we

found to organize our macros without the possibility of acting on the directory structure.


If you are using autocall and your file is named user_management then it needs to have a macro definition in it for the macro %user_management. If what it contains is the definition of other macros then every time you call it those macro will be re-defined, which is just a waste.  It also makes the file more confusing because there is an extra level of nesting you need worry about.

%macro user_management;
%put NOTE: You can now use the macros %str( %user_add, %user_del, and %user_update.);
%mend user_mangement;

%macro user_add

%mend user_add;

...
Kurt_Bremser
Super User

I'd NEVER do that. Use the autocall (or any SAS code) library in the usual way (1 macro -> 1 file). Just think of the nightmare of keeping such a convolution in a versioning system.

sas-innovate-2024.png

Join us for SAS Innovate April 16-19 at the Aria in Las Vegas. Bring the team and save big with our group pricing for a limited time only.

Pre-conference courses and tutorials are filling up fast and are always a sellout. Register today to reserve your seat.

 

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
  • 2730 views
  • 8 likes
  • 7 in conversation