Assign pipe to other pipe

hi,
I just tried the following and was surprised it did not work:

`%myPipe%` <- `%>%`
"some text" %myPipe% print() 

The error says "Error in pipes[[i]] : subscript out of bounds". How would I assign a pipe to another "name".

Some background. I want to have my own pipe to make it possible to switch easily between the "regular" pipe %>% and the promises pipe %...>%

The error you describe happens to me (it seems the function looses a layer of sorts, becoming f(lhs, rhs)), to, so I did a little poking around:

library(magrittr)
`%mypipe%` <- magrittr::`%>%`

mtcars %mypipe%
  filter(cyl == 4)
#> Error in pipes[[i]]: subscript out of bounds

The two functions, below, should be the same (described in more detail below), run magritr:::pipe() to see the sourcecode:

If you take a look at the magrittr source code, you'll see that the non-exported function pipe() is used to define all the other pipes in the package (including %>%, which is made by assigning the function pipe() to it.

I point out that it's not exported, since, typically, if reassigning a function name, you'd use colon notation to do so:

new_fun_name <- package::function()

Inside of a package, there are often "helper functions" that accomplish tasks that come up while writing the package functions, but that aren't necessarily exported from the package.

If I use the actual source code from magrittr for pipes(), give it the new name %mypipe%, and try to use it, I get an error:

# From magrittr source code
# Create a pipe operator.
#
# This function is used to create all the magrittr pipe operators.
pipe <- function()
  {
    function(lhs, rhs)
    {
      # the parent environment
      parent <- parent.frame()
      
      # the environment in which to evaluate pipeline
      env    <- new.env(parent = parent)
      
      # split the pipeline/chain into its parts.
      chain_parts <- split_chain(match.call(), env = env)
      
      pipes <- chain_parts[["pipes"]] # the pipe operators.
      rhss  <- chain_parts[["rhss" ]] # the right-hand sides.
      lhs   <- chain_parts[["lhs"  ]] # the left-hand side.
      
      # Create the list of functions defined by the right-hand sides.
      env[["_function_list"]] <- 
        lapply(seq_along(rhss), 
               function(i) wrap_function(rhss[[i]], pipes[[i]], parent))
      
      # Create a function which applies each of the above functions in turn.
      env[["_fseq"]] <-
        `class<-`(eval(quote(function(value) freduce(value, `_function_list`)), 
                       env, env), c("fseq", "function"))
      
      # make freduce available to the resulting function 
      # even if magrittr is not loaded.
      env[["freduce"]] <- freduce 
      
      # Result depends on the left-hand side.
      if (is_placeholder(lhs)) {
        # return the function itself.
        env[["_fseq"]]
      } else {
        # evaluate the LHS
        env[["_lhs"]] <- eval(lhs, parent, parent)
        
        # compute the result by applying the function to the LHS
        result <- withVisible(eval(quote(`_fseq`(`_lhs`)), env, env))
        
        # If compound assignment pipe operator is used, assign result
        if (is_compound_pipe(pipes[[1L]])) {
          eval(call("<-", lhs, result[["value"]]), parent, parent)
          # Otherwise, return it.
        } else {
          if (result[["visible"]]) 
            result[["value"]] 
          else 
            invisible(result[["value"]])
        }
      }
    }
  }


## Assign pipe to `%mypipe%`
`%mypipe%`  <- pipe()
mtcars %mypipe%
  filter(cyl == 6)
#> Error in split_chain(match.call(), env = env): could not find function "split_chain"

Created on 2018-07-30 by the reprex package (v0.2.0.9000).

The error message comes from the fact that there's a function defined somewhere in the magrittr package, split_chain(), that I haven't defined in any environment for %mypipe%.

Looking at the source code, I can tell that split_chain() is also not an exported function. In addition to the fact that there's no #' @export roxygen tag, it's also not listed as an exported function in the NAMESPACE.

If you add split_chain() there's at least one more function missing.

3 Likes

hmm, ok.

My plan was to be able to switch easily between "%>%" and "%...>% dependent on whether I want to run my app sync or async.

Is there another way to (maybe with a custom pipe) to switch easily between %...>% and %>% depending on a global option. All my attempts failed and I'd be glad for some input.

You might consider writing a package for yourself to do so— I'd recommend looking at the source code for other "pipe-defining" functions and/or packages, e.g. the Bizarro pipe, the magrittr source code (which this https://r-posts.com/pipes-in-r-tutorial-for-beginners/ post goes through nicely).

Hopefully someone else will have other ideas.

2 Likes

One idea:
As async programming should use library(promises), library(future) and a plan(...) call, you may be able to do %>% behavior only by controlling the plan call. If you use plan("sequential") for example, everything should be sync.

See choosing a launch method and other documentation on promises and future :package:

If this work, you'll only have to change the plan for execution.

1 Like

Also please consider our S3 extensible wrapr dot arrow pipe, it has a lot of user control features.