Skip to content

Possible (ab)use of lexical scoping in R ?

5 messages · Duncan Murdoch, Brian Ripley, Emmanuel Charpentier +1 more

#
Dear list,

I wish to define a set of functions *auxilliary* to another set of
"main" ones, and I wonder if there is some "clever" way do do this using
lexical scoping. Looking for that in the list's archives did not get me
easily understood answers. Perusing MASS (1st, 2nd, 3rd and 4th
editions!) and "Programming S" wasn't of much help either...

R easily allows to create functions local to *another* function, as in :

foo<-function(x,y,...) {
  bar<-function(a,...) {
  ...
  }
  gee<-function(t,u,...) {
  ...
  }
  t<-foo(y)
  u<-gee(t,x,..)
}

In this (pseudo-)example, bar() and gee() are known in foo() but unknown
in the main R environment, which is a Good Thing (TM) for my purposes ;
however, they are redefined in each call to foo(), which entails some
serious overhead. Furthermore, they cannot be used by any other function.

What I want to do is so create a set of (user-invisible) auxilliaries
used by another set of (user-visible) "main" functions. I might also
wish sometimes to create a such a set of data.

(Common) Lisp and Scheme allow this easily. For example, in Common Lisp,
I could use :

(flet ((bar (a)(...))(gee (t u)(...)))
  (defun foo(x y)( ...))
  (defun quux(m n ...)(...)))

Now (barring syntax errors I may have slipped in the above
pseudo-example (my Lisp is rusty)), foo and quux are known in the main
environment, can both call bar and gee, which are not visible. Lisp also
allows me to do a similar thing for "data" (with let()) and even macroes
(with macrolet()). Variants such as let*() allow, IIRC, to play tricks
with evaluation order (e. g. mutually calling "local" functions).

I am aware that one may achieve the same thing in R by creating a
package with its own namespace and exporting relevant items.However, in
my case, that would be trying to cut one's steak with a sawmill's ribbon
saw.

Are there way(s) to create a new environment, defining local functions
(or data) in this environment and the "main" functions in the parent
environment (or the global one) while still in the local environment ?

					Emmanuel Charpentier

PS : I'd appreciate Cc's to my address, since I am not on the list and
read it through the Web interface.

PPS : Shouldn't "S programming" be a bit overhauled ? at the time of its
writing, R 0.90 was current...
#
Emmanuel Charpentier wrote:
Yes, you can do this using lots of surgery on environments and resetting 
the parent environments of functions, but it's far easier to just create 
a package, because R does all the work for you when you ask for a 
namespace.  What's so hard about that?

If you really want to "roll your own" namespace, read the language 
manual sections on environments very carefully.  If you don't understand 
something that's written there (or something there appears not to be 
correct), please let me know.

Duncan Murdoch
#
On Sat, 21 May 2005, Emmanuel Charpentier wrote:

            
Well, `S Programming' (sic) is about S, and S is not lexically scoped, 
only the R dialect is (and much of it was not when that was written as 
functions in packages were re-parented).

Look at ?local for one way to do this.  However, I _would_ use a namespace 
for anything which required more than one public function.  Here is 
another (closely related) idea:

myenv <- new.env()
assign("bar", function(a,...) {}, envir = myenv)
assign("gee", function(t,u,...) {},  envir = myenv)
foo <- function(x,y,...) {
    t <- bar(y)  # I hope you meant
    u <- gee(t, x,..)
}
environment(foo) <- myenv
rm(myenv)
Not so: most of the effort is in the parsing which is done once.  I think 
you would find it hard to measure the overhead, which is counteracted by 
faster searching.  E.g.
[1] 1.35 0.00 1.35   NA   NA
## add an internal copy of ls()
[1] 1.3 0.0 1.3  NA  NA

appears to show a small negative overhead.
You seem unaware of how little difference that has made -- very little is 
superseded, although some additions could be made.  Revisions have 
been planned (and updates written) but more progress depends on the first 
author's health and time.
#
Dear List,

I asked how to create a set of functions (and maybe variables) shared by
another set of functions but hidden from the "main" environment.

Duncan Murdoch and Brian Ripley advised to use the package creation
system. Brian ripley (and someone else, offlist) also pointed me to the
local() function, which creates new environments with specified
contents, and which I was unaware of (btw, when this function has been
introduced ? It is mentioned neither in MASS 4th edition index, nor in
'S Programming' index).

After re-reading the available docs (which I may have misunderstood...),
I come to the following conclusions :

	- The package creation is the most elegant and portable form. Unless I
am mistaken, it entails however some administrative overhead (creation
of a directory structure, R CMD installation*, etc ...).

	- Using local() is a (semi-) kludge, easy to use in one-file disposable
works. It might be more error-prone than package creation.

	- It has been pointed to me that manipulating environment (via local()
or otherwise), in a very Abelson-&-Sussmann-like way, allowed to create
OO-oriented code, somewhat different from S3 and S4 class mechanisms.

Since repeated experiences have proved to my satisfaction that I am
piss-poor at top-down design, I will probably use the environment
manipulation for initial head-scratching phase, switching to package
creation at the formalization phase.

A big "thank you" to all respondents, whose answers have been *very* useful.

					Emmanuel Charpentier
#
Emmanuel Charpentier wrote:
I think everybody remembers that local() has been introduced in R-0.65.0 
(those who do not remember can simply look into the file OONEWS).

I like the two books as well, but I don't think they can be complete in 
the sense of describing *all* R functions.

I'd like to recommend the "package way". Working with envrionments and 
local() does not seem to be the R way - and it is very confusing to read 
code that refers to a couple of different environments ...

Uwe Ligges