[Contents] [TitleIndex] [WordIndex

Scoping of variables in Scilab

This is a FAQ, the answer cannot be taken for obvious, so it is worth to write some lines about it.

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

Commented example:

a=1   // this is level_0
b=2
x(1)=45
function c=foo(d)  // when this is executed, we'll be at level_1
  b                //enough to create a local b, which duplicates the upper one
  c=a              // uses the existing "a" at upper level; defines the output value
  e=d              // creates a new local variable "e", which disappears on return
  f=e
  x(3)=56          // note that at this point x=[0 0 56] because of 3. above, *not* [45 0 56]
  f=resume(e)      // copies the level_1 "e" into the level_0 variable "f", and leaves the function
endfunction
g=foo(3)  // calls the function with input 3, which is assigned to variable d inside the function
          //  its result is assigned to the level_0 variable "g"
f         // At the end, the function also created a level_0 variable "f"   

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


Comments about resume

(by jpc) resume also causes a function to return, i.e. instructions past a resume are never executed. Thus, there isn't really a way to put variables in the caller's namespace and to continue within the function. Since Scilab execution is single threaded, the variable passed at the upper level will be useful only when the code has returned there too; however, an instruction which just places named variables in the caller namespace and keeps going, could lead to syntax and memory efficiency in particular cases. For example, if an hypotetical command resumevar would exist:

allocate a big outvar
function a=foo
  do some calculation
  create a bigvar
  outvar=resumevar(bigvar)
  destroy bigvar to reclaim memory
  go on computing using memory
  a=final result
endfunction

Also, for instance a function which loads an unspecified number of variables from a file would benefit, since

while %t
  read a variable
  resumevar(variable)
  if end_of_file or read-error return
end

would be more efficient and easier than collecting the variable in a growable list, and having to unpack the list on return.


2022-09-08 09:27