Date: Fri, 13 Apr 2012 19:48:16 +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 unquoting with SCL open() (long)
In-Reply-To: <201204131926.q3DGtCug007227@willow.cc.uga.edu>
Content-Type: text/plain; charset="Windows-1252"
Feature or simply an oddity? I think its more of an oddity or fi you will a bug
in how the interface between the two languages are working. Trust me it wouldnt be
the first time. Prior to 9.2 there was a similar issue with the PRX functions and macro quoting.
You could run a PrxMatch on a Quoted macro variable and it wouldnt pop the quoting before
it sent the value over to the Perl API. Thus it would return the wrong position in the target
string for the match to start. After some discussion with the developer it was decided to
pop the quoting and then requote the returned value if it was needed.
Toby Dunn
If you get thrown from a horse, you have to get up and get back on, unless you landed on a cactus; then you have to roll around and scream in pain.
“Any idiot can face a crisis—it’s day to day living that wears you out”
~ Anton Chekhov
> Date: Fri, 13 Apr 2012 15:26:12 -0400
> From: qmcmullen.sas@GMAIL.COM
> Subject: Re: macro unquoting with SCL open() (long)
> To: SAS-L@LISTSERV.UGA.EDU; tobydunn@HOTMAIL.COM
>
> Thanks Toby,
>
> I'll have to think more about what your solution is doing. I certainly
> agree that:
>
> >sometimes SAS pops the macro quoting
> >off the value at the most inconvient times.
>
> But I'm stuck feeling like the issue here is a "feature" of the open()
> function.
>
> Here is a two-line example:
>
> %put %sysfunc(open (in(where=(var="%nrstr(%Something)"))));
> %put %sysfunc(length(in(where=(var="%nrstr(%Something)"))));
>
> LOG:
> 46 %put %sysfunc(open (in(where=(var="%nrstr(%Something)"))));
> WARNING: Apparent invocation of macro SOMETHING not resolved.
> 0
> 47 %put %sysfunc(length(in(where=(var="%nrstr(%Something)"))));
> 28
>
> So open() function is unmasking the value, but the length() function is not.
>
> Isn't that odd/surprising/bug-ish?
>
> --Q.
>
>
>
>
>
> On Fri, 13 Apr 2012 19:04:33 +0000, toby dunn <tobydunn@HOTMAIL.COM> wrote:
>
> >Quentin,
> >
> >Just surrounding the value for %type in the Nobs call looks to solve the
> problem.
> >
> >The intial %Nrstr hides the % sign from macro processor in the macro call,
> >however, once it gets to the data step code there is nothing specified to
> hide
> >it any more.... So a second %Nrstr is needed to hide it from the data step
> >parser. The long and short of it is sometimes SAS pops the macro quoting
> >off the value at the most inconvient times.
> >
> >
> >%macro report2(data=,type=);
> >%if %nobs(&data(where=(type=%Nrstr("&type"))))=0 %then %do;
> >data _null_;
> >file print;
> >put "There were no records in &data with type=&type";
> >run;
> >%end;
> >%else %do;
> >title1 "Printout of &data where Type=&Type";
> > proc print data=&data;
> > where type="&type";
> > run;
> > title1;
> >%end;
> >
> >Toby Dunn
> >
> >
> >If you get thrown from a horse, you have to get up and get back on, unless
> you landed on a cactus; then you have to roll around and scream in pain.
> >
> >�Any idiot can face a crisis�it�s day to day living that wears you out�
> >~ Anton Chekhov
> >
> >
> >
> >> Date: Fri, 13 Apr 2012 18:39:34 +0000
> >> From: bd9439@ATT.COM
> >> Subject: Re: macro unquoting with SCL open() (long)
> >> To: SAS-L@LISTSERV.UGA.EDU
> >>
> >> Hi Quentin,
> >>
> >> I think the problem is caused by the fact that your "report2" macro is
> passing a parameter that has a string embedded with double quotes. I'm not
> the right person to try and explain the how's or why's, but changing that
> line to use single-quotes instead will eliminate your warning message:
> >>
> >> %macro report2(data=,type=);
> >>
> >> %if %nobs(&data(where=(type=%str(%')&type%str(%'))))=0 %then %do;
> >> data _null_;
> >> file print;
> >> put "There were no records in &data with type=&type";
> >> run;
> >> %end;
> >> %else %do;
> >> title1 "Printout of &data where Type=&Type";
> >> proc print data=&data;
> >> where type="&type";
> >> run;
> >> title1;
> >> %end;
> >>
> >> I suppose you could also create another macro put single quotes around a
> string and add that to your kit.
> >>
> >> Also, I have a slight "issue" with your NOBS macro: it will fail with
> even more possibly confusing error messages if the dataset doesn't exit. If
> dsid is equal to zero after the open function, then data set does not exist
> (or cannot be opened for some reason, like a permission). You can code
> around that to deal with the situation directly (like printing your own
> error message to the log and not executing the attrn and close functions).
> >>
> >> Good luck,
> >>
> >> Bob
> >>
> >> -----Original Message-----
> >> From: SAS(r) Discussion [mailto:SAS-L@listserv.uga.edu] On Behalf Of
> Quentin McMullen
> >> Sent: Thursday, April 12, 2012 2:28 AM
> >> To: SAS-L@listserv.uga.edu
> >> Subject: Re: macro unquoting with SCL open() (long)
> >>
> >> Of course the user doesn't need to know how many obs to make their
> report.
> >> Of course they don't need %nobs. And of course they don't even need the
> >> macro language at all.
> >>
> >> I wasn't asking "how best can the user make the report"?
> >>
> >> Instead, was using %nobs as an example of a case where I am surprised by
> the
> >> apparent unquoting/unmasking performed by the open() function. Looking at
> >> %nobs, and applying what I think I know about macro quoting, I think it
> >> should work without producing a warning message.
> >>
> >> --Q.
> >>
> >>
> >> On Wed, 11 Apr 2012 22:54:38 -0500, Data _null_; <iebupdte@GMAIL.COM>
> wrote:
> >>
> >> >I knew it all along. :-) You don't need to know how many obs so you
> >> >don't that silly %NOBS macro. All you need to know is NONE or NOT.
> >> >
> >> >data test;
> >> > input Year Type $14. Value;
> >> > cards;
> >> >2001 AbsoluteChange 10
> >> >2002 AbsoluteChange 20
> >> >2003 AbsoluteChange 30
> >> >2001 %Change 5
> >> >2002 %Change 10
> >> >2003 %Change 15
> >> >;
> >> >run;
> >> >
> >> >
> >> >%macro report(data=,type=);
> >> > %local hasobs;
> >> > %let hasobs=1;
> >> > data _null_;
> >> > if _n_ eq 1 and eof then do;
> >> > file print;
> >> > put "There were no records in &data with type=&type";
> >> > call symputX('hasobs',0,'L');
> >> > end;
> >> > stop;
> >> > set &data end=eof;
> >> > where type eq "&type";
> >> > run;
> >> > %if &hasobs %then %do;
> >> > title1 "Printout of &data where Type=&Type";
> >> > proc print data=&data;
> >> > where type="&type";
> >> > run;
> >> > title1;
> >> > %end;
> >> > %mend report;
> >> >options mprint=1;
> >> >%report(data=test,type=AbsoluteChange)
> >> >%report(data=test,type=%nrstr(%Change))
> >> >%report(data=test,type=RelativeChange) /*no output produced*/
> >> >
> >> >
> >> >On 4/11/12, Quentin McMullen <qmcmullen.sas@gmail.com> wrote:
> >> >> Hi All,
> >> >>
> >> >> I think I mangled my description of the odd macro unquoting issue I
> >> >> encountered, so want to try again from scratch.
> >> >>
> >> >> Imagine a user has a dataset:
> >> >>
> >> >> data test;
> >> >> input Year Type $14. Value;
> >> >> cards;
> >> >> 2001 AbsoluteChange 10
> >> >> 2002 AbsoluteChange 20
> >> >> 2003 AbsoluteChange 30
> >> >> 2001 %Change 5
> >> >> 2002 %Change 10
> >> >> 2003 %Change 15
> >> >> ;
> >> >> run;
> >> >>
> >> >>
> >> >> They write a simple macro to write a report:
> >> >>
> >> >> %macro report(data=,type=);
> >> >>
> >> >> title1 "Printout of &data where Type=&Type";
> >> >> proc print data=&data;
> >> >> where type="&type";
> >> >> run;
> >> >> title1;
> >> >>
> >> >> %mend report;
> >> >>
> >> >> %report(data=test,type=AbsoluteChange)
> >> >> %report(data=test,type=%nrstr(%Change))
> >> >> %report(data=test,type=RelativeChange) /*no output produced*/
> >> >>
> >> >> The output from these calls is correct, and the log is clean. And
> >> >> then they decide that if they specify a TYPE which is not found in the
> >> >> data, they want a note in the output file. Luckily, they remember
> >> >> they have a coporate autocall library, which has a macro %nobs(). So
> >> >> they update their macro to be:
> >> >>
> >> >> %macro report2(data=,type=);
> >> >>
> >> >> %if %nobs(&data(where=(type="&type")))=0 %then %do;
> >> >> data _null_;
> >> >> file print;
> >> >> put "There were no records in &data with type=&type";
> >> >> run;
> >> >> %end;
> >> >> %else %do;
> >> >> title1 "Printout of &data where Type=&Type";
> >> >> proc print data=&data;
> >> >> where type="&type";
> >> >> run;
> >> >> title1;
> >> >> %end;
> >> >>
> >> >> %mend report2;
> >> >>
> >> >> %macro nobs(data);
> >> >> /*macro function in autocall library to return # obs in a dataset*/
> >> >> %local nobs dsid rc;
> >> >> %let dsid=%sysfunc(open(&data));
> >> >> %let nobs=%sysfunc(attrn(&dsid,NLOBSF));
> >> >> %let rc=%sysfunc(close(&dsid));
> >> >> &nobs
> >> >> %mend nobs;
> >> >>
> >> >> %report2(data=test,type=AbsoluteChange)
> >> >> %report2(data=test,type=%nrstr(%Change))
> >> >> %report2(data=test,type=RelativeChange)
> >> >>
> >> >> The output from these calls is correct. But when they look at the
> >> >> log, they now get a warning from the second invocation:
> >> >> 301 %report2(data=test,type=%nrstr(%Change))
> >> >> WARNING: Apparent invocation of macro CHANGE not resolved.
> >> >>
> >> >> The user is confused by this warning. They've quoted %Change when
> >> >> they passed in the value, so why would it be unquoted? After
> >> >> investigating, they realize that the problem is somewhere in %nobs(),
> >> >> so they call the guy who maintains %nobs() and say "you need to fix
> >> >> %nobs() because it's causing a spurious warning message in my log."
> >> >>
> >> >> And I think the user is right. While they could write %report2()
> >> >> differently, it's not the job of the macro function writer to tell
> >> >> people how to write their own macros. To my mind, the problem is in
> >> >> %nobs. The problem is that for some reason the line:
> >> >> %let dsid=%sysfunc(open(&data));
> >> >> is unquoting the value of &data. And adding a bunch more quoting
> doesn't
> >> >> help:
> >> >> %let dsid=%qsysfunc(open(%superq(data)));
> >> >>
> >> >> So now for the questions:
> >> >> 1. Do you agree that it is surprising that the open() function is
> >> >> unquoting &data (even when it is called by %qsysfunc)?
> >> >> 2. Is there a way to change the definition of %nobs so that it will
> >> >> preserve the user's quoting, so that the user will not get a warning
> >> >> message from: %report2(data=test,type=%nrstr(%Change)) ?
> >> >>
> >> >> Thanks,
> >> >> --Q.
> >> >>
> >
|