Nicole White Nicole White - 3 months ago 28
R Question

How to override exported function from R package listed in Imports

My package's

DESCRIPTION
file has
httr
in its Imports directive:

Imports:
httr (>= 1.1.0),
jsonlite,
rstudioapi


httr
exports an S3method for
length.path
.

S3method(length,path)


And it's defined as:

#' @export
length.path <- function(x) file.info(x)$size


In my package I have objects that I assign the class "path" to. Every time I assign the class "path" to any object, regardless of whether or not I ever call
length()
on the object, this is printed to stdout:

Error in file.info(x) : invalid filename argument


Here's some reproducible code everyone can run:

> sessionInfo()
R version 3.3.1 (2016-06-21)
Platform: x86_64-apple-darwin13.4.0 (64-bit)
Running under: OS X 10.11.5 (El Capitan)

locale:
[1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8

attached base packages:
[1] stats graphics grDevices utils datasets methods base

loaded via a namespace (and not attached):
[1] tools_3.3.1

> thing = 1:5
> class(thing) = 'path'

> requireNamespace('httr')
Loading required namespace: httr

> sessionInfo()
R version 3.3.1 (2016-06-21)
Platform: x86_64-apple-darwin13.4.0 (64-bit)
Running under: OS X 10.11.5 (El Capitan)

locale:
[1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8

attached base packages:
[1] stats graphics grDevices utils datasets methods base

loaded via a namespace (and not attached):
[1] httr_1.2.1 R6_2.1.2 tools_3.3.1

> thing = 1:5
> class(thing) = 'path'
Error in file.info(x) : invalid filename argument


I've tried catching it in a
try
but that doesn't work:

set_class = function(obj, c) {
class(obj) = c
return(obj)
}

thing = 1:5
thing = try(set_class(thing, 'path'), silent=TRUE)


Yields:

Error in file.info(x) : invalid filename argument


I've tried
assignInNamespace
to override the function:

base_length = function(obj) {
return(base::length(obj))
}

assignInNamespace('length.path', base_length, 'httr')
thing = 1:5
class(thing) = 'path'


But I get
Error: evaluation nested too deeply: infinite recursion / options(expressions=)?


When I use
httr
functions in my package I use them with
httr::function
so I'm not sure how this
length.path
function is leaking into my namespace and overriding the base length function. I've also tried explicit
@importFrom httr function
for each function that I use instead of using
httr::function
but that doesn't work either.

I also found this:

https://support.bioconductor.org/p/79059/

But the solution seemed to be to edit the source code of
httr
, which I can't do since my package imports it. How can I get around this?

AEF AEF
Answer

One possibility could be to create a function length.path() in your own package. If the base type of your path-objects is compatible with base::length() you could just unclass it to avoid infinite recursion:

length.path <- function(x) length(unclass(x))

However, this is potentially slow compared to a direct call to base::length() because it copies the object and needs method dispatch two times.