mlocal               package:mvbutils               R Documentation

_M_a_c_r_o-_l_i_k_e _f_u_n_c_t_i_o_n_s

_D_e_s_c_r_i_p_t_i_o_n:

     'mlocal' lets you write a function whose statements are executed
     in its caller's frame, rather than in its own frame.

_U_s_a_g_e:

     # Use only as wrapper of function body, like this:
     # my.fun <- function(..., nlocal=sys.parent()) mlocal( expr)
     # ... should be replaced by the arguments of "my.fun"
     # expr should be replaced by the code of "my.fun"
     # nlocal should always be included as shown
     mlocal( expr) # Don't use it like this!

_A_r_g_u_m_e_n_t_s:

    expr: the function code, normally a braced expression

_D_e_t_a_i_l_s:

     Sometimes it's useful to write a "child" function that can create
     and modify variables in its parent directly, without using
     'assign' or '<<-' (note that '<<-' will only work on variables
     that exist already). This can make for clearer, more modular
     programming; for example, tedious initializations of many
     variables can be hidden inside an 'initialize()' statement. The
     definition of an 'mlocal' function does not have to occur within
     its caller; the 'mlocal' function can exist as a completely
     separate R object.

     'mlocal' functions can have arguments just like normal functions.
     These arguments will temporarily hide any objects of the same name
     in the 'nlocal' frame (i.e. the calling frame). When the 'mlocal'
     function exits, its arguments will be deleted from the calling
     frame and the hidden objects (if any) will be restored. Sometimes
     it's desirable to avoid cluttering the calling frame with
     variables that only matter to the 'mlocal' function. A useful
     convention is to "declare" such temporary variables in your
     function definition, as defaultless arguments after the 'nlocal'
     argument.

     The 'nlocal' argument of an 'mlocal' function- which must ALWAYS
     be included in the definition, with the default specified as
     'sys.parent()'- can normally be omitted when invoking your
     'mlocal' function. However, you will need to set it explicitly
     when your function is to be called by another, e.g. 'lapply'; see
     the third example. A more daring usage is to call e.g.
     'fun.mlocal(nlocal=another.frame.number)' so that the statements
     in 'fun.mlocal' get executed in a completely different frame. A
     convoluted example can be found in the (internal) function
     'find.debug.HQ' in the 'debug' package, which creates a frame and
     defines a large number of variables in it, by calling
     'setup.debug.admin(nlocal=new.frame.number)'.

     'mlocal' functions can be nested, though this gets confusing. By
     default, all evaluation will happen in the same frame.

     Note that (at least at present) all arguments are evaluated as
     soon as your 'mlocal' function is invoked, rather than by the
     usual lazy evaluation mechanism. Missing arguments are still OK,
     though.

     If you call 'return' in an 'mlocal' function, you must call
     'local.return' too.

     Frame-dependent functions (sys.parent()) etc. will not do what you
     expect inside an 'mlocal' function. In R 1.8 at least, you need to
     shift the normal index by 3 to get what you'd expect, so that
     'sys.call(-3)' inside an 'mlocal' function will return the call to
     the 'mlocal' function, and 'sys.function( sys.parent(3))' will
     return the 'mlocal' function definition. You can get the expected
     results for the _caller_ via 'mvb.sys.parent' with no shift, etc.-
     unless the caller is itself an 'mlocal' function.

     'on.exit' works as you might expect, i.e. in the 'mlocal' function
     only. Calls to 'on.exit' in the 'mlocal' function will _not_ alter
     the exit code in the caller.

     See R-news 2001 #3 (1/3) for another closely related approach to
     "macros".

_V_a_l_u_e:

     As per your function; also see 'local.return'.

_A_u_t_h_o_r(_s):

     Mark Bravington

_S_e_e _A_l_s_o:

     'local.return', 'do.in.envir', and R-news 1/3

_E_x_a_m_p_l_e_s:

     # Tidiness and variable creation
     init <- function( nlocal=sys.parent()) mlocal( sqr.a <- a*a)
     ffout <- function( a) { init(); sqr.a }
     ffout( 5) # 25
     # Parameters and temporary variables
     ffin <- function( n, nlocal=sys.parent(), a, i) mlocal({
      # this "n" and "a" will temporarily replace caller's "n" and "a"
      print( n)
      a <- 1
      for( i in 1:n)
      a <- a*x
      a
      })
     x.to.the.n.plus.1 <- function( x, n) {
      print( ffin( n+1))
      print( n)
      print( ls())
      }
     x.to.the.n.plus.1( 3, 2) # prints as follows:
     # [1] 3 (in "ffin")
     # [1] 27 (result of "ffin")
     # [1] 2 (original n)
     # [1] "n" "x" (vars in "x.to.the..."-- NB no a or i)
     # Use of "nlocal"
     ffin <- function( i, nlocal=sys.parent()) mlocal( a <- a+i )
     ffout <- function( ivec) { a <- 0; sapply( ivec, ffin, nlocal=sys.nframe()) }
     ffout( 1:3) # 1 3 6

