4

I'm trying to make a simple macro that checks whether a specific macro variable is either missing or does not exist. Normally, this would require two statements: a %symexist, and if it does exist, additional logic to detect whether it's a null value. The below code combines all of that into one.

%macro isnull(macvar);
    %sysevalf(%superq(%superq(macvar)) NE %str(), boolean);
%mend isnull;

Problem

I cannot use %isNull() in a %if statement, because the returned value always seems to be a character. This behavior differs if it's in open code or within a macro itself.

What I've tried

I've narrowed it down to the macro not resolving as a numeric value. I've tried everything from enclosing it with %sysfunc(putn()) to %cmpres() to %sysfunc(compress()). If it's in open code, it is numeric. If it's in another macro, it's character. You can see it with this code:

/* Miss2 resolves incorrectly as character */
%macro check;
    %let miss1=%sysevalf(%superq(asdf) =, boolean);
    %let miss2=%isNull(asdf);

    %put Miss1: %datatyp(&miss1);
    %put Miss2: %datatyp(&miss2);
%mend;
%check;

/* Miss2 resolves correctly as numeric */
%let miss1=%sysevalf(%superq(asdf) =, boolean);
%let miss2=%isNull(asdf);

%put Miss1: %datatyp(&miss1);
%put Miss2: %datatyp(&miss2);

Want

I want to be able to use this in a %if statement to check whether a macro both exists and is not blank simultaneously.

%macro foo;
    %if(%isNull(sysuserid) = 1) %then %put sysuserid exists;
    %if(%isNull(asdffdsa) = 0) %then %put asdffdsa does not exist;

    %if(%isNull(sysuserid) > 0) %then %put this should resolve;
    %if(%isNull(asdffdsa) > 0) %then %put this should not resolve;
%mend;
%foo;
Stu Sztukowski
  • 10,597
  • 1
  • 12
  • 21
  • Taking a look at it, but to start with a misconception, macro variables do not have 'types' - they are _all_ text. – Joe May 02 '17 at 18:11
  • If you want to treat %MISSM() as if it is a function it cannot generate a semi-colon!! – Tom May 02 '17 at 18:22

1 Answers1

2

The problem you have here is that your macro has a semicolon in it. See this:

174  %macro check;
175      %let miss1=%sysevalf(%superq(asdf) NE %str(), boolean);
176      %let miss2=%missm(asdf);
177
178      %put &miss1. Miss1: %datatyp(&miss1);
179      %put &miss2. Miss2: %datatyp(%unquote(&miss2));
180  %mend;
181  %check;
WARNING: Apparent symbolic reference ASDF not resolved.
WARNING: Apparent symbolic reference ASDF not resolved.
0 Miss1: NUMERIC
0; Miss2: CHAR

Note the ;? Compile this instead:

%macro missm(macvar);
    %sysevalf(%superq(%superq(macvar)) NE %str(), boolean)
%mend missm;

and you get:

185  %macro check;
186      %let miss1=%sysevalf(%superq(asdf) NE %str(), boolean);
187      %let miss2=%missm(asdf);
188
189      %put &miss1. Miss1: %datatyp(&miss1);
190      %put &miss2. Miss2: %datatyp(%unquote(&miss2));
191  %mend;
192  %check;
WARNING: Apparent symbolic reference ASDF not resolved.
WARNING: Apparent symbolic reference ASDF not resolved.
0 Miss1: NUMERIC
0 Miss2: NUMERIC

I'll also add that I think you should not skip the %symexist. You get a warning in the log the way you're doing it here, that's easily avoided.

%macro missm(macvar);
  %if %symexist(&macvar.) %then
    %sysevalf(%superq(%superq(macvar)) NE , boolean)
  %else
    0 
%mend missm;

You'll also note I remove your unnecessary %str() which doesn't really do anything. See Chang Chung's seminal paper, Is This Macro Parameter Blank, for why (and for some more great information, if you haven't already read it).

Finally - I think I would suggest renaming your macro and/or reversing the direction. %if %missm says to me 'if this macro variable is missing', which is the opposite of what you're telling: TRUE is returned if it is NOT missing. %missm should return true for EQ [blank], or NOT %symexist; it should return false for [defined and contains a value].

Joe
  • 62,789
  • 6
  • 49
  • 67