with vs. attach
On Mon, May 9, 2016 at 7:12 AM, peter dalgaard <pdalgd at gmail.com> wrote:
On 09 May 2016, at 02:46 , Bert Gunter <bgunter.4567 at gmail.com> wrote:
... To be clear, Hadley or anyone else should also feel free to set me straight, preferably publicly, but privately if you prefer.
Not really to "set anyone straight", but there are some subtleties with mode call objects versus expression objects and formulas to be aware of. E.g.,
a <- 2
do.call("print", list(a*pi))
[1] 6.283185
do.call("print", list(quote(a*pi)))
[1] 6.283185
do.call("print", list(expression(a*pi)))
expression(a * pi)
do.call("print", list(~a*pi))
~a * pi Thing is, if you insert a call object into a parse tree, nothing is there to preserve its nature as an unevaluated expression. Similarly, in
call("print", quote(a*pi))
print(a * pi) the result is identical to quote(print(a * pi)), so when evaluated, quoting is not seen by print(). As far as I understand, this is also the reason that for math in ggplot, you may need as.expression(bquote(....)). In general, I think that a number of things in R had been more cleanly implemented using formulas/expression objects than using substitution and lazy evaluation, notably subset and offset arguments in lm/glm. It would have been so much cleaner to have lm(math ~ age, data = foo, subset = ~ sex=="1") than the current situation where lm internally chops its own head off and substitutes with model.frame, then evaluates the call to model.frame() which in turn does eval(substitute(subset), data, env). Of course, at the time, ~ was intended specifically for Wilkinson Rogers type formulas; "abusing" it for other kinds of expressions is something of an afterthought.
Yeah, to my mind, the cool thing about formulas is that they provide a concise way to capture an environment and an expression, and then Wilkinson Rogers are just a special case. It's obvious impossible to go back and change how lm() etc works now, but I'm reasonably confident that lazyeval provides a strong foundation going forward. The quasiquotation stuff is particularly important - and unquote-splice makes it possible to do things that are impossible with bquote(). (Of course, unquote-splice could be added to bquote(), but I think you'll still run into issues with environments) Hadley