Skip to content

recode_factor does not handle !!! #3390

@dan87134

Description

@dan87134

A code snippet like this

dplyr::recode_factor(x, !!! layer_key)

produces an error that says !level_key is an invalid argument type

This is the result of a question on https://community.rstudio.com/t/using-recode-factor-with-quasi-quotation/5761/5

Here is a repro

library(magrittr)
library(dplyr)
#> 
#> Attaching package: 'dplyr'
#> The following objects are masked from 'package:stats':
#> 
#>     filter, lag
#> The following objects are masked from 'package:base':
#> 
#>     intersect, setdiff, setequal, union
set.seed(100)
x <- sample(head(LETTERS, 3), 10, replace = TRUE) %>% factor
x
#>  [1] A A B A B B C B B A
#> Levels: A B C
level_key <- list("Be", "Cool", "Amigo") %>% set_names(c("B", "C", "A"))    # set factor re-level 
level_key2 <- list(B = "Be", C = "Cool", A = "Amigo")

dplyr::recode_factor(x, !!!level_key)
#> Error in !level_key: invalid argument type

Created on 2018-03-03 by the reprex package (v0.2.0).

The problem is the use of c(...) inside of rcode_factor. Here is my analysis of the problem.

The problem is buried inside of recode_factor. It is that only functions that are implemented to use quosures can properly interpret !!!

Here is where the problem is in recode_factor:

dplyr:::recode_factor
#> function (.x, ..., .default = NULL, .missing = NULL, .ordered = FALSE) 
#> {
#>     recoded <- recode(.x, ..., .default = .default, .missing = .missing)
# ----------------------------The . problem is with c() ----
#>     all_levels <- unique(c(..., recode_default(.x, .default, 
#>         recoded), .missing))
#>     recoded_levels <- if (is.factor(recoded)) 
#>         levels(recoded)
#>     else unique(recoded)
#>     levels <- intersect(all_levels, recoded_levels)
#>     factor(recoded, levels, ordered = .ordered)
#> }
#> <environment: namespace:dplyr>

Created on 2018-03-03 by the reprex package (v0.2.0).

The problem is in the Combine, c(), function. Although in !!! layer_key !!! looks like an operator or in !!!(layer_key) it looks like a function it is neither.

It depends on the function getting the !!! layer_key in an ... argument to do something like enquo(...) so that standard evaluation is bypassed. It is enquo(or one of it's friends) that interprets !!! to turn a list into individual dot arguments.

But c() is a primitive function so it just does standard evaluation of !!! level_key which, in effect, produces a syntax kind of error.

Here is an example of a function that tries to use !!! with c()

suppressPackageStartupMessages(library(tidyverse))
f2 <- function(...) {
    c(...)
}
level_key <- list("Be", "Cool", "Amigo") %>% set_names(c("B", "C", "A"))    # set factor re-level 

f2(!!! level_key)
#> Error in !level_key: invalid argument type

Created on 2018-03-03 by the reprex package (v0.2.0).

I don't see a workaround for this.

Metadata

Metadata

Assignees

No one assigned

    Labels

    featurea feature request or enhancement

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions