Search code examples
sassas-macro

Inconsistent Macro Variable Data Type


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;

Solution

  • 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].