moodymudskipper
moodymudskipper

Reputation: 47320

Macro to assign default values, avoid collision of variable names

Here's a small macro I want to call at the start of my macro functions.

It is the equivalent of %if not %length(&x) %then %let x = &val.

I want to use it as it's more readable and will help me to parse my code to build documentation (Which I need to do with regex as I can't install external softwares).

%macro def
/*---------------------
Assign default value
---------------------*/
(_x_data_x_  /* variable name (to be passed raw without &) */
,value       /* default value */
);
%if not %length(&&&_x_data_x_) %then %let &_x_data_x_ = &value;
%mend;

Here's how it works:

%macro test(a,b);
  %def(b,&a)
  %put "&b";
%mend;

%test(%str(,)); /* prints "," */

I chose the unusual parameter name _x_data_x_ because the macro fails when it's fed a value equal to the parameter's name (i.e. if my b parameter was named _x_data_x_).

Can I make it really safe, apart from choosing obscure names ?

Upvotes: 1

Views: 320

Answers (1)

Richard
Richard

Reputation: 27508

That is the correct approach.

You could make the macro more robust by adding checks:

 %* Prevent self reference because 
 %* assignment will not bubble to containing scope;

 %if %upcase(%superq(x_data_x)) eq X_DATA_X %then %do;
   %put ERROR: x_data_x=%superq(x_data_x) is not allowed;
   %abort cancel;
 %end;

 %* Prevent reference to non-existent because
 %* assignment will automatically localize 
 %* and not bubble to containing scope;

 %if not %symexist (%superq(x_data_x)) %then %do;
   %put ERROR: x_data_x=%superq(x_data_x) is invalid;
   %put ERROR: %superq(x_data_x) does not exist in callee scope;
   %abort cancel;
 %end;

Upvotes: 2

Related Questions