[Rd] Behaviour of environment(foo)<- (PR#1509)

Luke Tierney luke@stat.umn.edu
Fri, 3 May 2002 09:26:33 -0500

On Fri, May 03, 2002 at 11:49:25AM +0100, Jonathan Rougier wrote:
> Peter Dalgaard BSA wrote:
> > 
> > J.C.Rougier@durham.ac.uk writes:
> > 
> > > Hi Everyone,
> > >
> > > I've noticed that setting the environment of a function from a package
> > > actually creates a copy of that function in .GlobalEnv and sets the
> > > environment on this copy:
> > >
> > > > find(.profile)
> > > [1] "package:newblips"
> > > > environment(.profile) <- bb1$getEnv() # this is an environment
> > > > find(.profile)
> > > [1] ".GlobalEnv"       "package:newblips"
> > >
> > > I don't have a problem with this behaviour (now I understand it!) but
> > > I think that it would help to document it in the help file.  May I
> > > suggest that instead of
> > >
> > >      The assignment form sets the environment of the function or
> > >      formula `fun' to the `value' given.
> > >
> > > we have
> > >
> > >      The assignment form sets the environment of the function or
> > >      formula \code{fun} to \code{value} if \code{fun} is in the
> > >      current environment, otherwise it makes a copy of \code{fun} in
> > >      the current environment and sets the environment of the copy.
> > >
> > > I think that describes the current procedure: please correct me if I
> > > am wrong!
> > 
> > But this is generic behaviour for *all* attribute assignment. It makes
> > no sense to describe a specific instance of it. Consider
> > 
> > data(airquality)
> > f<-function() { x <- class(airquality)<-NULL; ls() }
> > f()
> > class(airquality)
> I understand.  However, I still think that the help page for environment
> is wrong!  Using "enviroment<-" does not necessarily set the environment
> of the function, as stated.  What happened to me is that I modified
> .profile in the package newblips and then re-assigned its environment
> but didn't see any change, because it was masked by the copy of .profile
> in .GlobalEnv that I didn't know I had.  That's quite a subtle outcome
> and I think that changing the environment help page would clarify this
> for other users.  J.

I agree with Peter.  The compound assignment process is quite complex
but it is uniform across compound assignments.  One way to describe it
is that

	f(x)<- y

does roughly (modulo some performance tweaks)

	if (! exists("x", inherits = FALSE))
            x <- x  # insures x is local
        x <- "f<-"(x, value = y)

The shorthand used in ?"environment<-" is the same as the shorthand
used in at lest some other assignment contexts, for example in ?"[<-":

     If one of these expressions appears on the left side of an
     assignment then that part of `x' is set to the value of the right
     hand side of the assignment.

I don't see much point in adding a substantial amount of legalese to
all of these, and doing so in only some places is likely to lead to
more confusion.

Specific to environment<-, if any change is warranted is might be to
add a disclaimer like

	Changing the environment of a function can have unexpected
	consequences.  There is usually a safer way to achieve what
	you are trying to do.

A similar warning would be appropriate for formals<- and body<-.  When
you define a function the usual way you cause a function expression
consisting of formals and body to be evaluated in a particular
environment.  That creates a closure in which the three pieces are
assembled in a consistent fashion.  Assigning to any one of them
separately is quite likely to lead to inconsistencies and is one
reason the internal code loses all attributes on the function when you
do this (in particular the 'source' attribute if there was one).  If
we get byte code compilation and f is a compiled function, then after

	environment(f)<- myenv

the value of f will have to either be an interpreted function or the
assignment will have to trigger a new compilation since the original
compilation will have used information from the original environment.

In fact, given these issues I would argue that a pretty strong case
can be made for eliminating formals<-, body<- and environment<- (at
least for functions), though there are some very limited circumstances
where they can be useful if used with care.

So, after all that, the real question: why are you doing this and are
you sure there isn't a better way?


Luke Tierney
University of Minnesota                      Phone:           612-625-7843
School of Statistics                         Fax:             612-624-8868
313 Ford Hall, 224 Church St. S.E.           email:      luke@stat.umn.edu
Minneapolis, MN 55455 USA                    WWW:  http://www.stat.umn.edu
r-devel mailing list -- Read http://www.ci.tuwien.ac.at/~hornik/R/R-FAQ.html
Send "info", "help", or "[un]subscribe"
(in the "body", not the subject !)  To: r-devel-request@stat.math.ethz.ch