Date: Thu, 8 Dec 2005 20:21:07 +0000
Reply-To: toby dunn <tobydunn@HOTMAIL.COM>
Sender: "SAS(r) Discussion" <SAS-L@LISTSERV.UGA.EDU>
From: toby dunn <tobydunn@HOTMAIL.COM>
Subject: Re: Macro quoting essentials
In-Reply-To: <1134067306.664342.61860@g47g2000cwa.googlegroups.com>
Content-Type: text/plain; format=flowed
Lei,
The problem that I have always saw with creating marcro definitions that use
pbuff or parmbuff (which ever you choose to call it) is that it leads to bad
macro design. Essentually what you end up with is some secret contract with
the rest of the code and the macro.
Admitedly using at the very least a positional parameter in the definition
is better than none at all (but not by much) positional parameters still
should not be used IMHO.
Consider:
Slightly modified from SAS Online Doc:
%macro printz(x) / parmbuff;
%let num=1;
%let dsname=%scan(&x,&num);
%do %while(&dsname ne);
proc print data=&dsname;
run;
%let num=%eval(&num+1);
%let dsname=%scan(&syspbuff,&num);
%end;
%mend printz;
With :
Direct copy from online doc:
%macro printz/parmbuff;
%let num=1;
%let dsname=%scan(&syspbuff,&num);
%do %while(&dsname ne);
proc print data=&dsname;
run;
%let num=%eval(&num+1);
%let dsname=%scan(&syspbuff,&num);
%end;
%mend printz;
Both besides sufferening from very inefficient coding mask what you are
passing and what macro var you are passing it too. Thus the readability and
maintainability of your code goes right down the drain. I have yet to find
a problem that could only be solved by using pbuff or positional parameters.
Now aside from the secret contract if you will, you also have the macro
design issue:
Lets start with the above example :
%macro printz/parmbuff;
%let num=1;
%let dsname=%scan(&syspbuff,&num);
%do %while(&dsname ne);
proc print data=&dsname;
run;
%let num=%eval(&num+1);
%let dsname=%scan(&syspbuff,&num);
%end;
%mend printz;
Okay as I see it there are several things wrong here no declaring the macro
vars local or global (local is prefered). %let this %do that heck my head
starts to hurt just looking at it.
A simpler solution is as follows:
%macro printz (DSNList = ) ;
%local I Stop ;
%let Stop = %eval( %sysfunc( countc(&DSNList , ',') ) + 1 ) ;
%do I = 1 %to &Stop ;
proc print
data = %scan(&DSNList , &i , ',') ;
run ;
%end ;
%mend Printz ;
%printz(DSNList = %str(Red , Blue, Green) )
Now the Programmer who is calling the macro knows that he has commas in
thier text string and that is I think the right place to put the quoting.
On the other I seriuosly doubt that pbuff was ever truelly intended for the
person who hard codes a list of values iin but rather the programmer who
dynamically gets it from a list.
So to that end I say that a macro definition may be the wrong tool for the
job:
Data Colors ;
length color $5 ;
do I = 1 to 5 ;
Color = 'Red' ;
output ;
end ;
do I = 1 to 8 ;
Color = 'Blue' ;
output ;
end ;
do I = 1 to 11 ;
Color = 'Green' ;
output ;
end ;
run ;
proc sort
data = Colors ;
by Color ;
run ;
data _null_ ;
set Colors ;
by color ;
if first.color then do ;
call execute('proc print') ;
call execute('data = '||color||';') ;
call execute('run;') ;
end ;
run ;
Toby Dunn
From: Lei Zhang <lzhang9830@YAHOO.COM>
Reply-To: lzhang9830@YAHOO.COM
To: SAS-L@LISTSERV.UGA.EDU
Subject: Re: Macro quoting essentials
Date: Thu, 8 Dec 2005 10:41:46 -0800
Hi, Toby,
You are right ! The result from the %length macro function in my
post should be 4 instead of 3.
I didn't track the discussion about macro quoting. I think Ian
has given an excellent summary about when or how to use macro quoting
functions. It is a very good guideance for most of SAS programers who
are writing or using SAS macros.
The reason that I say %length is a very special macro function
with any number of commas is that few people know that %length is a
special vararg macro that can take any number of macro parameters,
including commas. The other similiar build-in macro function are
%quote, %nrbquote, %sysfunc(cat(...)),, etc.
People can even develop their own vararg macros that take any
number of parameters without any problems. This can be done with macro
option pbuff. For example,
%macro test(X)/pbuff;
%put &x;
%mend;
You can call this macro like
%test(x1, x2, x3) or
%test(x1, x2, x3, x4, x5)
%test won't complain at all that you have assigned more parameters
that you defined.
This also remind me that if people develop vararg macros with pbuff
options, they most likely will use
%quote, %nrbquote macro functions in the implementation, they are,
however, not necessary because we alreadly have so many %Q- macros at
hand.
Have fun with vararg macros !
Lei