「静的と動的」 if 0 then set &data point = _n_ nobs = _nobs_ ; (1) 必要なコード以外に何もないという洗練は,比較によってはっきりする. dummy = 1 ; set &data point = dummy nobs = _nobs_ ; (2) ステートメントが2行に増えているが,それは本質的なことではない.(1)の洗練は set ステートメントが決して実行されないという点だ.そしてオブザベーション数を返すという目的は完全に達成されている.(2)のように第1オブザベーションを set しても,オブザベーション数を値として持つ変数は一般に保存されていない.オブザベーション数は第1オブザベーションにではなく,ディスクリプタ部分に書かれているのだから,目的にとっては余計な実行であり,プログラムを見た人にとっては「第1オブザベーションの中に何かあるのかな?」という思考をしばらく強制されることになる.CPUにとっては無に近いロスだが,もしも &data のオブザベーション数がゼロだったら, _error_ が真になり,put _all_ ; が動作して log を賑わすことになる. (1)は明らかに,SASスーパバイザ機能の理解に導かれたコードだと思われる.SASスーパバイザは,コンパイル・フェーズと実行フェーズに分かれて,DATAステップを遂行するから,コンパイル時に与えられる情報を獲得するにはコンパイルだけすればよい.(1)はコンパイルだけの静かなコードだが,(2)は実行フェーズでダイナミックに第1オブザベーションを set している.そして勿論このオブザベーションは「お呼びでない」. "SAS Guide" のこの1行は,唐突にもこんな詩句(コード)を連想させた. されば,われを揺り起こすなかれ・・・・・ 物曰ふなら,声低く語れ! −− ミケルアンジェロ ▼ if 0 .... というコードはトリッキーな印象を与える自己否定なので,現在は以下のように書くことにしている.ここでも set ステートメントは決して実行されず,ディスクリプタ情報をコンパイル時に獲得するという動作をしている.
%macro nobs( data ) ; /*-------------------------------------------------------- 指定したデ−タセットのオブザベーション数を調べて, グローバルマクロ変数 &nobs にその値を代入する. --------------------------------------------------------*/ options nodsnferr ; %global nobs ; %let nobs = 0 ; data _null_ ; call symput('nobs', put(__nobs, 12.) ) ; stop; set &data nobs = __nobs ; run; %let nobs = %left( &nobs ) ; %put note: global macro variable nobs = &nobs ; options dsnferr ; %mend nobs; |