[Rd] [External] Re: should base R have a piping operator ?
Lionel Henry
||one| @end|ng |rom r@tud|o@com
Mon Oct 7 21:14:21 CEST 2019
On 7 Oct 2019, at 18:17, Tierney, Luke <luke-tierney using uiowa.edu> wrote:
> Here is a stylized example:
The previous value of the binding should only be restored if it
existed:
g <- function(x, y) {
rlang::scoped_bindings(xx = x, .env = parent.frame())
y
get("xx") + 10
}
# Good
g(1, 2)
#> [1] 11
# Still good?
g(1, g(1, 2))
#> [1] 11
> If you play these games whether you get the result you want, or an
> obvious error, or just the wrong answer depends on argument evaluation
> order and the like.
I think the surprises are limited because the pattern has stack-like
semantics. We get in a new context where `.` gains a new meaning, and
when we exit the previous meaning is restored.
One example where this could lead to unexpected behaviour is trying to
capture the value of the placeholder in a closure:
f <- function(x) {
x %>% {
identity(function() .)
}
}
# This makes sense:
f("A")()
#> Error: object '.' not found
# This doesn't:
"B" %>% { f("A")() }
#> [1] "B"
> Not to mention that you would be telling users they are not allowed
> to use '.' as a variable name for their own purposes or you would be
> polluting their environment with some other artificial symbol that
> they would see in debugging.
That's a good point. Debugging allows to move up the call stack before
the context is exited, so you'd see the last value of `.` in examples
of nested pipes like `foo %>% bar( f %>% g() )`. That could be confusing.
> Anything going in base needs to worry even about artificial cases.
> Yes, there are things in base that don't meet that standard. No, that
> is not a reason to add more.
Agreed. What I meant by artificial cases is functions making
questionable assumptions after peeking into foreign contexts etc.
I'm worried about what happens with important language constructs like
`<-` and `return()` when code is evaluated in a local context. That
said, I think binding pipe values to `.` is more important than these
particular semantics because the placeholder is an obvious binding to
inspect while debug-stepping through a pipeline. So evaluating in a
child is probably preferable to giving up the placeholder altogether.
Best,
Lionel
More information about the R-devel
mailing list