[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