LISTSERV at the University of Georgia
Menubar Imagemap
Home Browse Manage Request Manuals Register
Previous messageNext messagePrevious in topicNext in topicPrevious by same authorNext by same authorPrevious page (December 2002, week 3)Back to main SAS-L pageJoin or leave SAS-L (or change settings)ReplyPost a new messageSearchProportional fontNon-proportional font
Date:         Tue, 17 Dec 2002 11:53:17 -0500
Reply-To:     Ian Whitlock <WHITLOI1@WESTAT.COM>
Sender:       "SAS(r) Discussion" <SAS-L@LISTSERV.UGA.EDU>
From:         Ian Whitlock <WHITLOI1@WESTAT.COM>
Subject:      Re: macro design
Comments: To: "Fehd, Ronald J. (PHPPO)" <rjf2@CDC.GOV>
Content-Type: text/plain; charset="iso-8859-1"

Ron,

You are absolutely correct about where the semi-colon problem lies and raise good questions about design.

You changed my macro from

%MACRO BigIf(cond=x=1,consequent=put x=); if &cond then &consequent ; %MEND;

to yours saying

> Personally I would write such as a function: > %MACRO BigIf(cond=x=1,consequent=put x=); > &cond then &consequent > %MEND;

From the problem point of view, I point out that in the header my macro explicitly stated

purpose: generate a SAS IF statement.

You changed the requirements of the macro into making a partial statement and consequently the problem. In general, changing the problem is often the best solution, but not in my puzzles.

From a design point of view I have to ask you why you would write a macro that simply separates two arguments by the four letters THEN? Oops, perhaps you could ask almost the same question of me. However, my position is different. I wanted a simple example and hoped that you would fill in with thoughts of the more complex problem that I had in mind. So my answer is that I would not write such a macro at all, but that it represents a real problem.

In this trivial situation you removed the IF and the semi-colon from the macro turning the code into what I would call a SAS partial statement macro. In doing so, the calling code became clearer because the context is left to the user's IF rather than just the macro name while incidentally turning a null statement into something useful. Now the question is: In the real problem, the one I had in mind, is such a technique a good one? I agree it was a bit unfair of me to not be more explicit about my thoughts in the first place. You get an A for the first test. So let's try again, although this time I will have to drop your template for more serious work. Consider a somewhat more realistic need for a similar macro on the fictitious madman project.

%macro BigIf ( testroot = x , result = y , testvalue = 5 , mult = 3, max = 7 ) ; %* make the complex IF statement required throughout the code for the madman project ; %local i j cond /* the condition for the big if statement */ vars /* variable list used in the consequent */ ;

%let cond = &testroot&mult = &testvalue ; %let vars = &testroot&mult ; %do i = 2 %to &max ; %let j = %eval ( &mult * &i ) ; %let cond = &cond or &testroot&j = &testvalue ; %let vars = &vars &testroot&j ; %end ;

if &cond then do ; chkflag = 1 ; &result = sum (of &vars ) ; end ;

%mend BigIf ;

Here is the simple test code.

data _null_ ; retain a1-a50 10 ; %bigif ( testroot = a , result = b , testvalue = 10 , mult = 4, max = 10 ) put b= ; run ;

Now from a design point of view, I would consider it down right wrong to put the IF in the consuming code. Would you still suggest that the semi-colon on the final END statement be removed in order to feed your habit of adding null statements after macro calls? If so, I hope you are saying to yourself, "write reminder to add comment that the END statement must not be completed". Now I suggest that any time one has to add comments like that, it is a indication of a big violation in some principle.

In this macro, I think, that there is no reasonable way to interpret the macro as generating a partial SAS statement, consequently there is no reasonable way to introduce partial SAS statements without creating a design error; hence the need for a comment when removing the semi-colon.

I apologize for the complexity, but that is what I was trying to avoid when I first posed the problem.

Incidentally, I originally wrote the macro starting with IF. It is interesting to contrast the two styles of macro coding. I quickly erased the code embarrassed that I might even consider showing it in public. However I had already tested it, so it was still just a few recalls away. Here it is, JUST FOR COMPARISON, I know better than to write code like this.

%macro BigIf ( testroot = x , result = y , testvalue = 5 , mult = 3, max = 7 ) ; %* make the complex IF statement required throughout the code for the madman project ; %local i j ;

if &testroot&mult = &testvalue %do i = 2 %to &max ; %let j = %eval ( &mult * &i ) ;

or &testroot&j = &testvalue

%end ; then do ; chkflag = 1 ; &result = sum (of %do i = 1 %to &max ; %let j = %eval ( &mult * &i ) ; &testroot&j %end ; ) ; end ; %mend BigIf ;

IanWhitlock@westat.com

-----Original Message----- From: Fehd, Ronald J. (PHPPO) [mailto:rjf2@CDC.GOV] Sent: Monday, December 16, 2002 3:51 PM To: SAS-L@LISTSERV.UGA.EDU Subject: macro design

After spending several hours over the weekend talking to myself about this problem I casually present the incomplete transcript.

Subject: A.Word.A.Day--frangible frangible (FRAN-juh-buhl) adjective Readily broken; breakable. ... This week's theme: kangaroo words, words that have a joey (a smaller word with a similar sense) within them. The word "frangible" has three generations of kangaroos: its joey "fragile" which in turn has its own little one "frail".

You can never solve a problem on the level on which it was created. -Albert Einstein, physicist, Nobel laureate (1879-1955)

while reading Kopka & Daly's A Guide to LaTeX I come across the notation that some commands are fragile while others are robust.

Ian Whitlock <WHITLOI1@WESTAT.COM> writes in Subject: tip macro function CLOCK V2 debugging > I wrote the following code. > Please do not criticize the inanity of the code. > It is not meant to be good principled code. > It is meant to demonstrate a point.

%MACRO BigIf(cond=x=1,consequent=put x=); if &cond then &consequent ; %MEND;

which I would like to continue the discussion on whether a preposition or a semicolon is a good thing to end a sentence or a macro with.

/*test data

data w ;

do x = 1 to 3 ;

output ;

end ;

run ;

data sub ;

set w ;

%BigIf(cond=x=1,consequent=output sub);

run ;

/*test data closure*/

options mprint ;

data sub ;

set w ;

%BigIf(cond=x=1,consequent=output sub);

else

%BigIf(cond=x=3,consequent=put x=);

run ;

Ian, I wonder if this is the original example that you use to illustrate why you do not recommend ending macro calls with a semicolon?

At any rate I recommend ending macro calls with semicolons because the majority of my experience is writing macro procedures which contain one or more steps. I've had to change my thinking in the last week, due to your helpful critique, for which I am grateful.

I do not have much experience writing intra-date-step macros which are saved outside the program.

Your above example is in that gray area between function and procedure. Admittedly very close to the function end of the scale.

My question for discussion is what is correct or appropriate to keep in mind when asked for such code?

Personally I would write such as a function: %MACRO BigIf(cond=x=1,consequent=put x=); &cond then &consequent %MEND;

then to be used as:

data sub ;

set w ; if %BigIf(cond=x=1,consequent=output sub); else if %BigIf(cond=x=3,consequent=put x=);

run;

This gets around the gotcha of having a complete if statement in the macro and presents the user with a <macro call that looks like a SAS statement>.

I am aware of the issues behind the obvious misuse here: IF statements can be unary, and they can be independent.

The problem with ELSE is the IF statement becomes part of an ELSE-delimited list of IF statements i.e.: XOR(IF-1,IF-2,IF-3,...) and any ELSE IF-i must come immediately after the closure of IF-(i-1)

For those of you that are still reading, Ian's point was that using my style sheet, the code would generate a null statement <;> between IF-1 and IF-2 e.g. if <cond-1> then <consequent-1>; ;%*side effect of my style sheet; else if <cond-2> then <consequent-2>;

I wonder whether there's any way to keep idiots from asking us to write code that's fragile?

Ron Fehd the macro maven CDC Atlanta GA USA RJF2@cdc.gov

My computer must be broken: whenever I ask a wrong question, I get a wrong answer. -- Pot-Shots by Ashleigh Brilliant

Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the Universe trying to produce bigger and better idiots. So far, the Universe is winning. - Rich Cook


Back to: Top of message | Previous page | Main SAS-L page