[Scilab] Scilabの変数スコープについて

Scilabは、変数のスコープの扱いが独特だ。
関数を作るときには、注意しないとややこしいことになるので、知っておかないとまずいと思い、ドキュメントを訳してみた。

http://wiki.scilab.org/howto/global_and_local_variables
より

In what follows level_0 is the level of the interactive shell; level_1 is that of functions called from level_0, level_2 that of subfunctions of level_1, and so on.

local variables and scoping

  1. local variables, which are not defined at level_N, are inherited from upper levels
  2. local variables defined at level_N remain local at that level. If a level_N variable has the same name of an upper level variable, a transient duplicate variable is created at level_N
  3. local variables inherited from upper levels can be read with no overhead; but if they are written, a transient local with the same name is created (not returned back unless specifically required). Note that the transient variable is first initialized to []; thus if this variable is implicitly grown (by assigning array elements beyond the current size), the local transient overrides over the outer variable.
  4. the appearance of the variable on an empty line of a function (which would cause immediate display at level_0) is sufficient to create the local duplicate
  5. input values of the function are assigned to the corresponding local variables of the function
  6. output arguments of a function are assigned upon return, at the upper level, to those variables specified in the function call
  7. argument passing is thus by value, in common programming terms; however, as in 3., the value is not really copied unless needed; for reading only, passing is by reference. So to say, it is a "lazy" passing by value, as copying the value is delayed to when really needed in the progam flow.
  8. only for adequately written primitives and interfaces of primitives, there is an option of by value/by reference (see intppty)
  9. local variables can be returned to their immediate upper level with resume. The difference between resume and output arguments is that resume specifies the name of the upper variable which is assigned, output values are assigned to whatever name choosen at the caller level.
  10. the command for undefining local variables is clear

Global variables

  1. global variables can have the same name of local variables, and coexist (the two namespaces are separate)
  2. global variables are shared by all scopes in which they are declared global, respectless of their calling depth
  3. declaring a variable global in a function does not help in making an upper local variable with the same name visible in the function: the upper local is already visible, and a global declaration can have unexpected side effects
  4. only when a variable is declared global, assignments affect its global version
  5. if a variable is declared global, and a local variable with the same name already exists, the value of the local is copied to the newly created global
  6. if a variable is declared global, and a local variable with the same name does not exist, an empty matrix [] is created in the global namespace and a pointer to it is created in the local namespace.
  7. the command for undefining global variables is clearglobal

適当に訳してみた。よくわからないところは意訳になっているので、内容は保障しません。

level_0はインタラクティブシェルのレベルである。
level_1はlevel_0から呼び出された関数であり、level_2はlevel_1から呼び出されたサブ関数である。それ以降も同様。

ローカル変数とスコープ

  1. level_Nで定義されていないローカル変数は、上位のレベルから引き継がれる
  2. level_Nで定義されているローカル変数は、そのレベルに留まる。もし、level_Nの変数が上位レベルの変数と同じ名前である場合、一次的な複製がlevel_Nで作成される
  3. 上位レベルから引き継がれた変数は、オーバーヘッド無しに読み込むことができる。しかし、書き込みがある場合、一時的に同じ名前を持つ変数が作成される(特に指定されることがない限り上位レベルの値は更新されない)。この際に作成される一時的な変数の初期値は[]である点に注意すべきである。もし、この変数の領域が拡大する場合(配列の要素サイズが再定義されるような場合)、上位レベルの値は引き継がれない。
  4. 変数単体を記述したライン(level_0に内容が表示される)は、ローカルに複製を生成する
  5. 関数の引数は、ローカル変数になる
  6. 関数の戻り値は、関数を呼び出した上位レベルの変数になる
  7. 引数は値渡しでおこなわれるが、「3.」のような読み込みのみで複製の必要がない値は、参照渡しで行われる。値の複製が行われる「のろのろ」した値渡しは、プログラムを遅くする原因であるからである。
  8. 基本的には、値渡し・参照私のオプションは存在しない(intpptyを見よ)
  9. resumeを使うとローカル変数は上位レベルに戻すことができる。resumeと戻り値の違いは、resumeは上位レベルでの変数名を指定できるのに対し、戻り値は呼び出し側で名前を指定する
  10. ローカル変数を消去するコマンドはclearである

グローバル変数

  1. グローバル変数は、ローカル変数と同じ名前を持つことができ、同時に存在できる(2つの名前空間は分けられている)
  2. グローバル変数は、コールの深さによらず、すべてのスコープで共有される
  3. 関数内でグローバル変数を定義しても、上位レベルで同じ名前のローカル変数は生成されない。上位レベルに同名のローカル変数が存在する場合に予期せぬ影響が考えられるからである。
  4. 値がグローバルのみで定義される場合、値の割り当てはグローバルにのみ影響をあたえる
  5. グローバル変数を定義する時、同じ名前のローカル変数がすでにある場合には、ローカル変数の値がグローバル変数にコピーされる
  6. グローバル変数を定義する時、同じ名前のローカル変数がない場合には、空行列[]がグローバル名前空間に生成され、そこへのポインターがローカル名前空間に生成される
  7. グローバル変数を消去するコマンドはclearglobalである

え?そうだったの?ってところがいくつもある。

  • ローカル変数はサブ関数内にもスコープを持つ
    • ただし読み込み専用
    • 書き込むと同じ名前のローカル変数が作られる
      • その際空行列[]で初期化されるため、行列の一部を書き換えるような書き方はできない
      • 書き換えたとしても、上位レベルの値は変わらない


これを知らないと、変に悩むことがあるだろう。注意が必要だ。

  • 追記

後で気がついたが、これらのルールはFortran風のルールのようだ。Fortranは使ったことがないので気がつかなかった。MATLABも同様なのだろうか。