33

Background

I written an R package, and now a collaborator (recent CS grad who is new to R) is editing and refactoring the code. In the process, he is dividing up my functions into smaller, more generic functions.

What he is doing makes sense, but when I started with package.skeleton(), I had one file per function. Now, he has added functions on which the primary function depends, but that may have limited use outside the function itself.

He suggests that all the functions go into a single file, but I am against that because it is easier to do version control when we work on different files.

I have since started using roxygen to document each function within the text.

Question

What is the recommended way to handle functions: clearly the helper functions should stay with the the main function, but to what extent do I need to document helper functions?

The @export suggestion in the comments is helpful, but I am curious to know how others organize their code.

Community
  • 1
  • 1
David LeBauer
  • 31,011
  • 31
  • 115
  • 189
  • Could it be as easy as not exporting the helper functions? – Joshua Ulrich Mar 09 '11 at 17:58
  • @Joshua I don't know, I am not familiar with the how/what/why/where of exporting functions – David LeBauer Mar 09 '11 at 18:01
  • 7
    You might need a NAMESPACE file to specify which functions are user "visible" and which are not. You might try using a . in front of the functions you wish the user not to see and use "exportPattern("^[^\\.]")" in your NAMESPACE file in the root of your package structure –  Mar 09 '11 at 18:31
  • 11
    If you're using roxygen, it's better to explicitly `@export` the function that you want to export – hadley Mar 09 '11 at 21:28
  • 1
    +1 to hadley, glazed over the roxygen part! –  Mar 09 '11 at 22:03

1 Answers1

33

I cut up my functions under two conditions :

  1. when it improves readibility of the code of the main function, and/or
  2. when it avoids copy-pasting code, eg if the same code is used a couple of times within the same function.

I do include the so-called helper functions in the file of the main function, but only as long as those helper functions are not used in any other function. Actually, I consider them nested within the main function. I do understand your argument for version control, but changing the helper function comes down to changing the performance of the main function, so I see no problem in keeping them in the same file.

Some helper functions might be used in different other functions, and then I save them in their own file. Often I do export those functions, as they might be of interest for the user. Compare this to eg lm and the underlying lm.fit, where advanced users could make decent use of lm.fit for speeding up code etc.

I use the naming convention used in quite some packages (and derived from linux), by preceding every "hidden" function by a dot. So that makes

.helper.function <- function(x, ...){
    ... some code ...
}

main.function <- function(x, ...){
    ...some code, including .helper.function(y, ...)
}

I explicitly @export all functions that need exporting, never the helper functions. It's not always easy to judge whether a function might be of interest to an end user, but in most cases it's pretty clear.

To give an example : A few lines of code to cut off NA lines I consider a helper function. A more complex function to convert the dataset to the correct format I export and document.

YMMV

Joris Meys
  • 106,551
  • 31
  • 221
  • 263
  • 1
    Thanks! Having a non-exported helper function in an extra file, how do I source these helper files so that the main function can use them? After all, they are not exported and thus not visible to the user. – shosaco Jan 05 '19 at 17:27
  • 1
    @shosaco In the context of a package that doesn't matter. If you work outsice a package, i.e. just have a bunch of scripts with functions, then you have to source the helper files using `source()` before you use the main function. Keep in mind everything ends up in the global environment that way, so you can overwrite and/or delete the helper function by accident. – Joris Meys Jan 07 '19 at 15:27