2017年8月30日水曜日

そのマクロ変数、ローカル?グローバル?⑥パズルみたいな事例



今回のシリーズ記事を書いたのは、以下記事のパズルみたいな事例をみて「なるほど、面白いなぁ」と思ったのがキッカケでした。



マクロ変数を作成するときに引っかかった話 (晴れ時々SAS)
http://dengonmemo.blogspot.jp/2017/07/blog-post.html

data DT_TEST ;
    _AA=1 ; output ;
    _AA=2 ; output ;
    _AA=3 ; output ;
run ;
%macro MCR_TEST ;

    *----------  ローカルマクロを指定;
    %let _aa2=123 ;
    data _NULL ;
        set DT_TEST ;
     
        *----------  グローバルマクロを指定;
        call symputx("_aa2",_N_,"g") ;
    run ;
    *----------  マクロ変数を呼び出し;
    %put &_aa2 ;

%mend ;

*----------  1回目:ローカルマクロとしての値(123)が返る;
%MCR_TEST ;


*----------  2回目以降:グローバルマクロとしての値(3)を返す;
%MCR_TEST ;


マクロ「MCR_TEST」を1回目に実行した時と、2回目に実行した時とで、「%put &_aa2;」の戻り値が異なってしまってるよ。というものです。


先日SASユーザー総会で「晴れ時々SAS」を運営されている方に記事のせてもOKの許可を頂いたので、「何故戻り値が実行する度に変わってしまったのか」を解説したいと思います。




マクロ実行「1回目」の挙動


%let _aa2=123 ;

まずは以下記事で紹介したフローチャートの通り、ローカルマクロ変数「_aa2」が作成されます。
(同名のマクロ変数が既に定義されていないかチェックし、定義されていない場合はローカルマクロ変数になる。)
http://sas-boubi.blogspot.jp/2017/07/let.html



data _NULL ;
    set DT_TEST ;

    *----------  グローバルマクロを指定;
    call symputx("_aa2",_N_,"g") ;
run ;

以下記事で紹介している CALL SYMPUTX でグローバルマクロ変数「_aa2」が作成されます。
http://sas-boubi.blogspot.jp/2017/08/blog-post_28.html

この時点で、
・ローカルマクロ変数 「_aa2」= 123
・グローバルマクロ変数「_aa2」= 3
が作成されたことになりますね。


%put &_aa2 ;

以下記事のフローチャートの通り、マクロ内でローカルとグローバルに同名のマクロ変数が存在する場合、ローカルマクロ変数の値を優先して展開するので、「%put &_aa2;」の戻り値は ”123” となります。
http://sas-boubi.blogspot.jp/2017/08/blog-post_17.html


マクロが終了すると、ローカルマクロ変数は消去されるので、グローバルマクロ変数「_aa2」= 3 だけが残ります。



マクロ実行「2回目」の挙動


%let _aa2=123 ;

マクロを1回目に実行したときにグローバルマクロ変数「_aa2」が残っていることに注目してください。
以下記事フローチャートの通り、グローバルに同名のマクロ変数が存在するので、グローバルマクロ変数を上書きします。
http://sas-boubi.blogspot.jp/2017/07/let.html


data _NULL ;
    set DT_TEST ;

    *----------  グローバルマクロを指定;
    call symputx("_aa2",_N_,"g") ;
run ;

CALL SYMPUTX でグローバルマクロ変数「_aa2」を上書きします。


この時点で、
・グローバルマクロ変数「_aa2」= 3
のみが存在することになりますね。


%put &_aa2 ;

グローバルマクロ変数しか存在しないので、戻り値は当然グローバルマクロ変数の値 ”3” が返されます。



パズルを解くみたいに入り組んじゃってますね。
実際にこのパズルに悩んで質問を頂くことがあります。


0 件のコメント:

コメントを投稿