Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is using assign bad?

Tags:

r

assign

This post (Lazy evaluation in R – is assign affected?) covers some common ground but I am not sure it answers my question.

I stopped using assign when I discovered the apply family quite a while back, albeit, purely for reasons of elegance in situations such as this:

names.foo <- letters
values.foo <- LETTERS
for (i in 1:length(names.foo))
  assign(names.foo[i], paste("This is: ", values.foo[i]))

which can be replaced by:

foo <- lapply(X=values.foo, FUN=function (k) paste("This is :", k))
names(foo) <- names.foo

This is also the reason this (http://cran.r-project.org/doc/FAQ/R-FAQ.html#How-can-I-turn-a-string-into-a-variable_003f) R-faq says this should be avoided.

Now, I know that assign is generally frowned upon. But are there other reasons I don't know? I suspect it may mess with the scoping or lazy evaluation but I am not sure? Example code that demonstrates such problems will be great.

like image 715
asb Avatar asked Jul 09 '13 22:07

asb


3 Answers

Actually those two operations are quite different. The first gives you 26 different objects while the second gives you only one. The second object will be a lot easier to use in analyses. So I guess I would say you have already demonstrated the major downside of assign, namely the necessity of then needing always to use get for corralling or gathering up all the similarly named individual objects that are now "loose" in the global environment. Try imagining how you would serially do anything with those 26 separate objects. A simple lapply(foo, func) will suffice for the second strategy.

That FAQ citation really only says that using assignment and then assigning names is easier, but did not imply it was "bad". I happen to read it as "less functional" since you are not actually returning a value that gets assigned. The effect looks to be a side-effect (and in this case the assign strategy results in 26 separate side-effects). The use of assign seems to be adopted by people that are coming from languages that have global variables as a way of avoiding picking up the "True R Way", i.e. functional programming with data-objects. They really should be learning to use lists rather than littering their workspace with individually-named items.

There is another assignment paradigm that can be used:

 foo <- setNames(  paste0(letters,1:26),  LETTERS) 

That creates a named atomic vector rather than a named list, but the access to values in the vector is still done with names given to [.

like image 131
IRTFM Avatar answered Oct 09 '22 03:10

IRTFM


As the source of fortune(236) I thought I would add a couple examples (also see fortune(174)).

First, a quiz. Consider the following code:

x <- 1
y <- some.function.that.uses.assign(rnorm(100))

After running the above 2 lines of code, what is the value of x?

The assign function is used to commit "Action at a distance" (see http://en.wikipedia.org/wiki/Action_at_a_distance_(computer_programming) or google for it). This is often the source of hard to find bugs.

I think the biggest problem with assign is that it tends to lead people down paths of thinking that take them away from better options. A simple example is the 2 sets of code in the question. The lapply solution is more elegant and should be promoted, but the mere fact that people learn about the assign function leads people to the loop option. Then they decide that they need to do the same operation on each object created in the loop (which would be just another simple lapply or sapply if the elegant solution were used) and resort to an even more complicated loop involving both get and apply along with ugly calls to paste. Then those enamored with assign try to do something like:

curname <- paste('myvector[', i, ']')
assign(curname, i)

And that does not do quite what they expected which leads to either complaining about R (which is as fair as complaining that my next door neighbor's house is too far away because I chose to walk the long way around the block) or even worse, delve into using eval and parse to get their constructed string to "work" (which then leads to fortune(106) and fortune(181)).

like image 38
Greg Snow Avatar answered Oct 09 '22 04:10

Greg Snow


I'd like to point out that assign is meant to be used with environments.

From that point of view, the "bad" thing in the example above is using a not quite appropriate data structure (the base environment instead of a list or data.frame, vector, ...).

Side note: also for environments, the $ and $<- operators work, so in many cases the explicit assign and get isn't necessary there, neither.

like image 24
cbeleites unhappy with SX Avatar answered Oct 09 '22 04:10

cbeleites unhappy with SX