-
Notifications
You must be signed in to change notification settings - Fork 50
2. Coding guide: R
Feel free to contact me if you have any troubles, questions, comments, wishes, etc.
myVariableName
- variable names should be nouns
-
fPath
(instead of filePath, fileName, filename, path)
- don't repeat yourself
- keep functions as simple as possible (generally each function does one thing)
- each function should either returns an object, or has a side-effect
- processing functions should return the processed object in the same format (such that the processing functions could be combined in a pipeline)
- function arguments defining a window length (or similar): argument in time or length unit (not in number of points/pixels)
doThatThing()
- function name should be a verb
- Favour explicit, lengthy names, over short, implicit, names
- Make sure that function families are identified by a common prefix, not a common suffix.
- private function starts with a dot. Example:
.myPrivateFunction()
.
- with generic method: use exactly the same arguments as the existing methods. To know the arguments of a method use
args(myMethod)
. - empty slot should have length 0:
length(object@mySlot) = 0
. Therefore, use:-
character(0)
(instead of""
, becauselength("") = 1
), -
matrix(ncol = 0, nrow = 0)
, -
numeric(0)
, -
integer(0)
, list()
-
- spacing
average <- mean(feet/12 + inches, na.rm = TRUE) sqrt(x^2 + y^2) x <- 1:10 base::get y ~ x tribble( ~col1, ~col2, "a", "b" ) # and not average<-mean(feet/12 + inches,na.rm=TRUE) sqrt(x ^ 2 + y ^ 2) x <- 1 : 10 base :: get y~x
- Line length: 80 characters
Split file names, warning and error messages, e.g.,
warning("This a very, very, very long", "warning")
- Assignment: Use <-, not =, e.g.,
x <- 10 + y # and not x = 10 + y
- Indenting
for long code lines:
if(y < 0 && debug){ message("y is negative") } if(y == 0){ if(x > 0){ log(x) }else{ message("x is negative or zero") } }else{ y^x }
long_function_name <- function(a = "a long argument", b = "another argument", c = "another long argument") { # As usual code is indented by two spaces. y <- a * b + c }
-
use
paste0()
instead ofpaste(..., sep = "")
-
use
message()
inside a function instead ofcat()
orprint()
! -
invisible()
: Return a (temporarily) invisible copy of an object, used in plot function -
missing()
: check if an arguments is missing -
Don't want to pass
...
-arguments to a function? Solution: use a wrapper function, where the args after...
are the args that you don't want to have in the function. e.g.:lPoints <- function(..., log, axes, frame.plot, panel.first, panel.last) { points(...) }
-
unname()
-
Reset the plot parameters to their default values
op <- par(no.readonly=TRUE) # plot... par(op)
- Use
seq_along(x)
to protect against instances wherex
is empty:for(i in seq_along(x)){ doThatThing(i) }
- Use
apply()
,lapply()
,Mapply()
,outer()
,Reduce()
,Filter()
,Map()
,Negate()
,Position()
,replicate()
, etc. when possible
- head: first parameter =
x
(GPR object) - slot check (optional)
- argument check
- private function applied to the data:
.fun(x@data)
- update the slots if necessary
- update processing history:
proc(x) <- getArgs()
return(...)
The function getArgs()
when put inside a method captures the method name, its argument names and the values passed to the arguments. Therefore, it is possible to keep track of the processing applied to the GPR data by storing the captured information into the @proc
slot. The adopted notations is:
functionName//arg1=val1+arg2=val2+arg3=val3
The method must have as first argument an object of the class GPR
. Here an example:
setMethod("dcshift", "GPR", function(x, u, FUN = mean){
shift <- matrix(apply(x[u,],2, FUN), nrow = nrow(x),
ncol=ncol(x), byrow = TRUE)
x <- x - shift
proc(x) <- getArgs()
return(x)
}
)
To insert "manually" an additional processing step, use the function addArg()
(but normally you don't need it):
proc(x) <- getArgs( addArgs = list('arg10' = val10, 'arg11' = val11))
For example:
proc(x) <- getArgs( addArgs = list('eigenvalues' = 1:10, 'w' = 30.4))
In R, the “fail fast” principle is implemented in three ways:
-
Be strict about what you accept. For example, if your function is not vectorised in its inputs, but uses functions that are, make sure to check that the inputs are scalars. You can use stopifnot(), the assertthat package, or simple if statements and stop().
-
Avoid functions that use non-standard evaluation, like subset, transform, and with. These functions save time when used interactively, but because they make assumptions to reduce typing, when they fail, they often fail with uninformative error messages. You can learn more about non-standard evaluation in non-standard evaluation.
-
Avoid functions that return different types of output depending on their input. The two biggest offenders are [ and sapply(). Whenever subsetting a data frame in a function, you should always use drop = FALSE, otherwise you will accidentally convert 1-column data frames into vectors. Similarly, never use sapply() inside a function: always use the stricter vapply() which will throw an error if the inputs are incorrect types and return the correct type of output even for zero-length inputs.