DATA Step, Macro, Functions and more

Macro Var resolution: Timing issue

Accepted Solution Solved
Reply
Respected Advisor
Posts: 4,674
Accepted Solution

Macro Var resolution: Timing issue

Hi all,

I try to understand why in below sample macro variable MyMvar doesn't resolve when using call execute().

I understand that this is a timing issue but as simple as the example is, I can't understand the why. Could someone please shed some light on it for me?

%macro testit();
  data _null_;
    call symputx('MyMvar','Test String','L');
    stop;
  run;

  data _null_;
    put "MyMvar: &MyMvar";
    stop;
  run; 

%mend;

data _null_;
  call execute('%testit()');
  stop;
run;

data _null_;
  _rc=dosubl('%testit()');
  stop;
run;
 

 

40         data _null_;
41           call execute('%testit()');
42           stop;
43         run;

WARNING: Apparent symbolic reference MYMVAR not resolved.
NOTE: DATA statement used (Total process time):
      real time           0.00 seconds
      cpu time            0.00 seconds
      

NOTE: CALL EXECUTE generated line.
1         + data _null_;     call symputx('MyMvar','Test String','L');     stop;   run;

NOTE: DATA statement used (Total process time):
      real time           0.00 seconds
      cpu time            0.00 seconds
      
1         +                                                                                data _null_;     put "MyMvar: &MyMvar";  
         stop;   run;


MyMvar: Test String
NOTE: DATA statement used (Total process time):
      real time           0.00 seconds
      cpu time            0.01 seconds

Thanks,

Patrick


Accepted Solutions
Solution
Thursday
Trusted Advisor
Posts: 1,159

Re: Macro Var resolution: Timing issue

Hi @Patrick,

 

The late Roland Rashleigh-Berry recommended: Use %nrstr() when you "call execute" a macro. And indeed, if you follow this advice the warning does not occur. What he wrote seems to explain what you have observed: "the macro call will be resolved internally" already within the data step containing the CALL EXECUTE statement. So, when the macro processor parses the code of macro TESTIT it stumbles across macro variable reference &MyMvar, hence the warning, because the data step defining MyMvar has not been executed yet (as macro resolution has not yet finished plus we are still in the "outer" data step).

 

With DOSUBL it's a different story because of the "parallel processing" even of data steps which it enables.

View solution in original post


All Replies
Super Contributor
Posts: 331

Re: Macro Var resolution: Timing issue

Solution
Thursday
Trusted Advisor
Posts: 1,159

Re: Macro Var resolution: Timing issue

Hi @Patrick,

 

The late Roland Rashleigh-Berry recommended: Use %nrstr() when you "call execute" a macro. And indeed, if you follow this advice the warning does not occur. What he wrote seems to explain what you have observed: "the macro call will be resolved internally" already within the data step containing the CALL EXECUTE statement. So, when the macro processor parses the code of macro TESTIT it stumbles across macro variable reference &MyMvar, hence the warning, because the data step defining MyMvar has not been executed yet (as macro resolution has not yet finished plus we are still in the "outer" data step).

 

With DOSUBL it's a different story because of the "parallel processing" even of data steps which it enables.

Super User
Posts: 6,632

Re: Macro Var resolution: Timing issue

[ Edited ]

CALL EXECUTE is generating two DATA steps.  However, it can't actually run either of them immediately.  Both of them have to wait until the current DATA step (the one that contains CALL EXECUTE) has finished.  Naturally, you just can't run another DATA step until the current DATA step has finished.  

 

Instead, SAS has to stack up the statements that CALL EXECUTE is generating, until the current DATA step has finished.  There's a problem stacking up the PUT statement, because &MYVAR doesn't exist yet.  It only exists after the current DATA step finishes, and the first generated DATA step completes.

Super User
Posts: 9,890

Re: Macro Var resolution: Timing issue

You might see it like that: call execute() pushes the code contained onto the same execution pipeline that the current data step is running in, while dosubl() creates a new, independent execution pipeline that only exists for the duration of the dosubl() call.

 

If I read it correctly, dosubl() has been added with SAS 9.4 and opens up a whole new way of thinking about timing. At least I can't find a reference in the docs for 9.3 and earlier.

---------------------------------------------------------------------------------------------
Maxims of Maximally Efficient SAS Programmers
How to convert datasets to data steps
How to post code
PROC Star
Posts: 1,449

Re: Macro Var resolution: Timing issue

You've already received some great answers.  Just to add a bit, I think the key idea is that when you use CALL EXECUTE to invoke a macro, it will execute the macro.  When the macro executes, it will generate any SAS code (data step code or whatever), resolve all the macro references, and put it on the input stack to be compiled and executed by the SAS data step compiler.  When the macro executes, it will also execute any macro statements immediately.  This causes the timing problem, because if the macro generates macro variables from data step code, the attempt to resolve the macro variables will be made before the macro variables have been generated.

 

If you use CALL EXECUTE to invoke a macro and hide the macro call in %NRSTR(), CALL EXECUTE will not actually execute the macro.  Instead, it just generates the call to the macro and puts the macro call on on the input stack.  The macro is executed after the data step with the call execute has completed.  This lets the timing work out.

 

Here is slightly revised sample code, with a %PUT statement added

 

%macro testit();
  data _null_;
    call symputx('MyMvar','Test String','L');
    stop;
  run;

  %put Macro %nrstr(%put) MyMVar: &MyMVar ;

  data _null_;
    put "Data step put MyMvar: &MyMvar";
    stop;
  run; 

%mend;

If you run it like:

%symdel MyMvar ;

data _null_;
  call execute('%testit()');
run;

The log shows that call execute generated the SAS code generated by %testit. So it executed %testit:

208  data _null_;
209    call execute('%testit()');
210  run;

WARNING: Apparent symbolic reference MYMVAR not resolved.
Macro %put MyMVar: &MyMVar
WARNING: Apparent symbolic reference MYMVAR not resolved.

NOTE: CALL EXECUTE generated line.
1   + data _null_;     call symputx('MyMvar','Test String','L');     stop;   run;


1   +                                                                                data _null_;
    put "Data step put MyMvar: &MyMvar";     stop;   run;

Data step put MyMvar: Test String

Warnings are thrown indicating that &MYMVAR could not resolve on the %PUT statement, or the first time it is seen on the PUT statement.  

Also, note that even though you asked CALL SYMPUTX to make a local macro variable, it still made a global macro variable. Because when CALL SYMPUTX executed, there was no local scope.

 

If you run like:

%symdel MyMvar ;

data _null_;
  call execute('%nrstr(%testit())');
run;

Call execute will generate the macro call, but won't actually execute the macro.  The log shows:

292  data _null_;
293    call execute('%nrstr(%testit())');
294  run;


NOTE: CALL EXECUTE generated line.
1   + %testit()


Macro %put MyMVar: Test String

Data step put MyMvar: Test String

Note that call executed generated the call to %testit, but did not actually executed %testit.  %Testit is executed after the data step with the call execute. So all the timing issues work out.  

 

I always use %NRSTR() when invoking a macro via call execute.  Not only does it make the macro timing work out, it also makes a cleaner log, where you can see the macro calls that were generated.

 

 

Super User
Posts: 10,689

Re: Macro Var resolution: Timing issue

Patrick,

I think @FreelanceReinhar get the point ,add %nrstr() to suppress the warning .

Respected Advisor
Posts: 4,674

Re: Macro Var resolution: Timing issue

Thank you all for your great answers.

☑ This topic is solved.

Need further help from the community? Please ask a new question.

Discussion stats
  • 7 replies
  • 140 views
  • 8 likes
  • 7 in conversation