4

I am currently developing a package in R with the "help" of devtools. That is, the package is getting loaded into R studio via load_all(path = ...) in this stage and my functions from the R directory are made available. So far so good. But when I try to implement a simple S3 hierarchy within my package, the dispatching will not work - it throws the following error:

Error in UseMethod("generic_function", obj) : no applicable method for 'generic_function' applied to an object of class "c('data.frame', 'myclass')"

However, when I implement the same generic function as well as its methods and load them in the current environment explicitly the dispatching will work.

I cannot explain what is going on under the hood here. The dispatching will simply not work when I load the package but it works when "loading it on the fly" in the environment.

I appreciate your help. BR

... as requested the code:

scaler <- function (solvertraj, ...) {
  UseMethod("scaler", solvertraj)
}

scaler.scale_multi <- function(solvertraj, ...){
  resls = list()
  ls = c("incumbant", "average.fitness")
  min_inc = min(solvertraj$incumbant)
  max_inc = max(solvertraj$incumbant)
  
  for(i in 1:length(ls)){
    tobe_scaled = ls[i]
    tmp = sapply(solvertraj[tobe_scaled], function(x){
      (x-min_inc) / (max_inc -min_inc)
    })
    resls[[i]] = tmp
  }
  #attr(solvertraj,'MIN_MAX_scaled') <<- TRUE
  return(resls)
} 

scaler.scale_other <- function(solvertraj, ...){
  res = list()
  plls = list()
  shapirols = list()
  resls = list()
  ls = c("incumbant", "average.fitness")
  
  for(i in 1:length(ls)){
    col = ls[i]
    # 1) shrink range
    tmp = sapply(solvertraj[col], function(x){
      x - min(solvertraj["incumbant"])
    })
    # 2) use natural logarithm
    tmp_2 = sapply(tmp, log)
    tmp_2[length(tmp_2)] <- 0L
    res[[i]] = tmp_2
    
    # TODO: fix
    plot_trans = plot(density(tmp_2))
    plls[[i]] = plot_trans
    
    tmp_test = shapiro.test(tmp_2)
    shapirols[[i]] <- tmp_test
  }
  
  resls = list.append(resls,
                      scales = res,
                      plots = plls,
                      shapirols = shapirols)

  #attr(solvertraj,'SHRINKAGE_scaled') <<- TRUE
  return(resls)
} 
gero
  • 119
  • 11
  • 1
    What does your `generic_function` look like? Or just show all the relevant code, otherwise troubleshooting is near impossible. – JonasV Aug 17 '20 at 12:17
  • There you: btw, I have tried the functions and they work. The problem really drills down to the loading of the function... (I guess). Much appreciate your help – gero Aug 17 '20 at 12:27
  • 7
    I had a similar issue. You may need to export the dispatched methods: `#' @export` above each – SmokeyShakers Aug 17 '20 at 12:30
  • okay, could you just real quick elaborate on this? so basically doing: #' @export above all three functions will do it? why? Thank you I will try now – gero Aug 17 '20 at 12:34
  • I have put [# '@export] but it still raises the same error. Do I have to include the NAMESPACE somehow? – gero Aug 17 '20 at 12:39
  • 3
    `@export` is a roxygen2 tag, which exposes functions of a package to the user. If a function isn't exported, it can not be accessed by the `UseMethod()` dispatcher. In general if writing a package it is necessary to document your functions most commonly using roxygen tags. In RStudio you can insert a "standard" roxygen block using the shortcut `Ctrl + Shift + Alt + R`. – JonasV Aug 17 '20 at 12:42
  • okay guys: thank you! I was putting roxygen 2 skeletons in all my R functions and converted them to .Rd files --> by this I got the NAMESPACE file and here I go: [S3method(scalerOwn,scale_multi) S3method(scalerOwn,scale_other)]! – gero Aug 17 '20 at 13:22
  • @SmokeyShakers it works. But I wonder why that should be done in case internally used generics. That really wired. – Indranil Gayen Feb 12 '21 at 07:28
  • @IndranilGayen I totally agree. It's something I learned to do because it works, not because I understand why. – SmokeyShakers Feb 12 '21 at 15:48

1 Answers1

2

The post is old, but this is an answer for people who'd face the same issue. I think the explanation might be you weren't using a proper workflow while using devtools:

  1. code your method print.myclass <- function(x, ...){}
  2. run document() before load_all() (this is how NAMESPACE will get properly updated)
  3. run load_all()

If you skip document() and only run load_all(), you'll load your print.myclass, you'll be able to call it directly with print.myclass(instance_myclass) and get the intended result. sloop::s3_dispatch(print(instance_myclass)) will confusingly tell you that it understands it should dispatch print to your method... but you'll get default print when calling print(instance_myclass)...

#' @export was probably not the problem here, even though S3 methods should be exported. It was probably due to incorrect NAMESPACE in your dev environment.

Marc C
  • 21
  • 3