Point/Counterpoint: Where should you put ODS SELECT and ODS OUTPUT statements?

4

ODS statements are global SAS statements. As such, you can put them anywhere in your SAS program. For maximum readability, many SAS programmers agree that most ODS statements should appear outside procedures in "open" SAS code. For example, most programmers agree that the following statements should appear outside of procedures:

ods graphics off;
ods html style=HTMLBlue;
ods listing close;

However, it is less clear whether the ODS SELECT and the ODS OUTPUT statements should appear. Should you put them outside of a procedure boundary, or inside?

I have tried to summarize both sides of the debate by using a Point/Counterpoint approach. The argument for putting ODS statements outside of procedures is summarized by Otis Outside. The argument for putting ODS statements inside procedures is summarized by Ingrid Inside. I thank participants on the SAS-L discussion forum and several colleagues at SAS for sharing their thoughts on this matter. Hopefully Ingrid and Otis represent your views fairly and faithfully.

POINT: ODS statements should appear outside procedures

By: Otis Outside


When you write a procedure statement, put your ODS SELECT and ODS OUTPUT statements outside the procedure, like this:

ods select ParameterEstimates FitStatistics;
ods output ParameterEstimates=PE;
proc reg data=Sashelp.Class;
   model weight = height age;
quit;

In this program, the ODS SELECT statement is used to limit the output of the subsequent procedure call. Only the ParameterEstimates table and the FitStatistics table will be displayed. Furthermore, the ODS OUTPUT statement specifies that the ParameterEstimates table will be written to a SAS data set.

ODS statements—like all global statements—should always appear outside of procedures. The only statements that should appear inside a procedure are the statements that apply to that procedure. (Notice that if you look at the procedure documentation, you will not find the global statements there!) If you put the TITLE statement and all ODS statements before the PROC statement, it is clear that they are global statements that will affect the subsequent procedure call.

Furthermore, in procedures that support an OUTPUT statement, it is potentially confusing to put an ODS OUTPUT statement inside the procedure because it looks so similar to the OUTPUT statement. Eliminate the possible confusion by putting the ODS OUTPUT statement outside the procedure.

Although Rick has described an example in which an ODS statement does not work when it follows an interactive procedure, this argument is nullified if programmers correctly end interactive procedures by using a QUIT statement. Programmers like me should not have to modify a logical programming convention just to protect against the possibility that someone else might not terminate a procedure correctly.

COUNTERPOINT: ODS statements should appear inside procedures

By: Ingrid Inside


When you write a procedure statement, put your ODS SELECT and ODS OUTPUT statements inside the procedure, like this:

proc reg data=Sashelp.Class;
   model weight = height age;
   ods select FitStatistics;
run;
   model weight = height;
   ods select ParameterEstimates;
   ods output ParameterEstimates=PE;
run;
quit;

The REG procedure is an interactive procedure. Every time it encounters a RUN statement, it processes the preceding statements and displays the results. When it terminates with the QUIT statement, any ODS OUTPUT data sets are closed. In the preceding statements, the FitStatistics table is displayed for the first model that is specified. The second MODEL statement changes the model. For the second model, the ParameterEstimates table AND the FitStatistics table are both displayed because the ODS SELECT statement acts cumulatively. However, the ODS OUTPUT statement creates a data set that contains only the parameter estimates for the second model.

You can't get this flexibility if you put the ODS statements outside of the procedure. To obtain the full power of the ODS system and interactive procedures, you should put the ODS statements inside the procedure. And once you start doing it for interactive procedures, it makes sense to maintain that convention for all procedures.

And I don't buy the argument that "it might be confusing" to put ODS statements inside a procedure. I think the opposite is true. An ODS statement doesn't actually do anything. It just sets up a condition in ODS. ODS then waits for the right procedure to come along and consume it. I think it is less confusing to put ODS statements inside the procedure that they affect. That's why I recommend that you use this convention for all procedures, not just the interactive procedures.

Lastly, Rick's example shows how you can get in trouble if you put ODS statements outside of a procedure. A good programmer practices defensive programming. By putting ODS statements inside of procedures, my programs are more robust.

Your turn

What do you say, readers? Do you agree with Otis or with Ingrid? What convention do you use for ODS SELECT and ODS OUTPUT statements? Why? Leave a comment.

Share

About Author

Rick Wicklin

Distinguished Researcher in Computational Statistics

Rick Wicklin, PhD, is a distinguished researcher in computational statistics at SAS and is a principal developer of PROC IML and SAS/IML Studio. His areas of expertise include computational statistics, simulation, statistical graphics, and modern methods in statistical data analysis. Rick is author of the books Statistical Programming with SAS/IML Software and Simulating Data with SAS.

4 Comments

  1. I think I'm firmly in the camp of Otis Outside. In part because by default ODS SELECT statement persists within a proc, across run groups. e.g.:

    proc reg data=Sashelp.Class;
    model weight = height age;
    ods select FitStatistics;
    run;
    model weight = height;
    ods select ParameterEstimates;
    run;
    model weight = age;
    run;
    model weight = age;
    ods select all;
    run;
    quit;

    Generally it's just confusing/misleading when global statements appear "inside" a step. Another example would be %let statements "inside" a data step.

    I think Otis also has a strong case for TITLE statements always being outside procs. Curious if Ingrid likes those inside as well?

    • Rick Wicklin

      Ingrid replies: I put the TITLE statement outside when it applies to multiple steps of an analysis. However, I put the TITLE statement inside of PROC SGPLOT because it affects the title of the graph. I sometimes use TITLE2 statements inside interactive procedures (within each RUN block) to help annotate the output.

  2. Stanley Fogleman on

    Rick - I'm sure you didn't intend this, but you neglected to mention the ODS parameters
    MATCH_ALL and PERSIST = PROC/RUN; I'm a great believer in the "ODS Sandwich" approach (which would correspond to your "outside" approach) and I never heard of the contents of the sandwich being outside the slices of bread, or at least not in an appealing way. Also, I think that modification and maintenance of code would be much more difficult if the "inside" approach were used. I predict an animated discussion.

    • Rick Wicklin

      Rick Replies: Yes, someone on SAS-L also mentioned the PERSIST= option. For people who are unfamiliar with this option, see p. 7 of the SAS Global Forum paper on ODS by Oltsik (2008), which has an example similar to Ingrid's.

      Ingrid replies: Hi Stanley! Regarding sandwiches, I am a big fan of "inside-out" sushi, where the rice is wrapped in the fish. And I think the fine folks at Sara Lee (a bread company) would argue that an inside-out sandwich can be delicious and nutritious! With respect to code maintenance, I've never had any trouble. When I cut and paste from one program file to another, the output in the new program is always correct because the output is controlled inside of the procedure block.

Leave A Reply

Back to Top