Here is a technical tip from one of our most respected
SAS gurus. Ian
has presented papers at NESUG for years and they
are always highly
anticipated. Ian also participates in the NESUG Code
Clinic and his
diagnoses and treatments can make any program
healthier.
Have you looked at SAS-L
http://listserv.uga.edu/archives/sas-l.html? You can
see many questions and answers to SAS problems
there. An important site for SAS programmers who
want search SAS-L or find SAS conference papers is
http://lexjansen.com/sugi/. A new site that should play
a prominent role for the SAS programmer is
http://sas.community.org/. Unfortunately the site was
not quite ready when this article was written.
Let's look at a macro design question that was hinted
at in the last week of March 2007 under the title "Help
with Macro Resolution" on SAS-L. The original
problem was to explain why a certain macro variable
reference wasn't resolving. However, my interest was
really in the issues of macro design that the code
raised.
Here is the original code:
%MACRO FT_GAINS(datatype=);
data counts;
/*----- some sas code ----*/
if smi > 10 then passflag='Y';
else passflag='N';
call symput("&datatype"||'_PASSFLAG',passflag);
run;
PROC PRINT DATA=COUNTS;
%if XXXX = "N" %then %do;
TITLE "WARNING - DATA DIMENSION "
"%upcase(&DATATYPE) HAS FAILED";
%end;
%else
%do;
TITLE"DATA DIMENSION %upcase(&DATATYPE)
HAS PASSED";
%end;
%mend;
The problem: the coder wants to know how to replace
the XXXX so that it will reference the macro variable
created with SYMPUT, &DATATYPE._PASSFLAG. For
example, %FT_GAINS(DATATYPE=IV) should cause
the macro variable, IV_PASSFLAG to be created.
The answer: use two more ampersands and include
the dot to end the reference to &DATATYPE, i.e. use
&&&DATATYPE._PASSFLAG. In the first scan of the
reference, the leading two ampersands are replaced
by one, &DATATYPE is resolved, and _PASSFLAG is
attached. In the second scan the variable's value is
returned.
Questions to think about:
1. What will be the title on the next reporting step when
this macro is invoked? For example, say the next step
is
proc means data = w ; run ;
Or worse what is the title on the macro's PROC PRINT
when the following code is
title "Important Means report for W" ;
proc means data = w ; run ;
2. Suppose that the DATA step finally assigns
IV_PASSFLAG the value, N. Why will the title still
be "DATA DIMENSION IV HAS PASSED"?
3. What is the danger when there is more than one
input observation going to COUNTS?
4. If SMI > 10 was evaluated more than once, which
one will determine the title?
5. The macro variable name,
&DATATYPE._PASSFLAG, is complex and contains
information. Is there anything in the code shown to
suggest that a complex name was needed?
6. The variable, &DATATYPE._PASSFLAG, is probably
local. Under what conditions would it not be local to
an execution of %FT_GAINS?
7. The number 10 was the magic value for
determining whether the situation was a pass or fail.
Should this number be a parameter of the macro?
8. Presumably there was some input data to the DATA
step. Do you think this data set reference should have
been specified in another parameter of the macro?
9. How many times should the macro variable,
&DATATYPE._PASSFLAG, be assigned? Assuming
there is more than one input observation to the DATA
step, how would you write the code to assign the
macro variable once?
10. The DATA step essentially decides which title to
use in the PROC PRINT. How could the macro be
rewritten to avoid making the decision again with %
IF/%ELSE code in the PRINT step?
Think about the questions. This exercise will help you
in approaching how you write your own macros. To
test answers to some of the simpler questions, you
might try a data set with one variable SMI having
values above and below 10. The author may be
contacted at Ian.whitlock@comcast.net.