Basics
Writing functions has several advantages over other types of writing code in R.For instance it helps coders to avoid repeating themselves. Other benefits are:
You can give a function an evocative name that makes your code easier to understand.
As requirements change, you only need to update code in one place, instead of many.
You eliminate the chance of making incidental mistakes when you copy and paste (i.e., updating a variable name in one place, but not in another).
As a general rule, You should consider writing a function whenever you’ve copied and pasted a block of code more than twice.
Function arguments
A function has two broad sets of arguments: one set supplies the data to compute on, and the other supplies arguments that control the details of the computation. For instance, in str_c(), multiple number of strings are data argument, and the details of the concatenation are controlled by sep and collapse.
Generally, data arguments should come first. Detail arguments should go on the end, and usually should have default values.
` function name <- function(data arguments, detail arguments){
}`
The default value should almost always be the most common value.
When you call a function, you typically omit the names of the data arguments, because they are used so commonly. If you override the default value of a detail argument, you should use the full name.
when you call a function, you should place a space around = in function calls, and always put a space after a comma, not before (just like in regular English). Using whitespace makes it easier to skim the function for the important components.
average <- mean(feet / 12 + inches, na.rm = TRUE)
Conditional execution
Since functions and conditional commands have similar style, I will first introduce conditional execution which can be also employed within a function. The, I will discuss the code style in next section.
An if statement allows you to conditionally execute code. It looks like this:
if (condition) {
# code executed when condition is TRUE
} else {
# code executed when condition is FALSE
}It is also possible to chain multiple if statements together:
if (this) {
# do that
} else if (that) {
# do something else
} else {
#
}We can use as much as else if needed but it is better to use switch() function to avoid very long series of chained if statements.
Another useful function that can often eliminate long chains of if statements is cut().
Code style
Both if and function should (almost) always be followed by squiggly brackets ({}), and the contents should be indented by two spaces.
An opening curly brace should never go on its own line and should always be followed by a new line.
A closing curly brace should always go on its own line, unless it’s followed by else. Always indent the code inside curly braces.
Example:
if (y < 0 && debug) {
message("Y is negative")
}
if (y == 0) {
log(x)
} else {
y ^ x
}Check and return values
Checking values: Sometimes, we may use invalid inputs in calling our functions. To avoid this problem, it’s often useful to make constraints explicit. It says we can use stop() command within an if statement to force the function to stop when the data is incorrect. For instance, when two input variables should be of the same length but they are not!
- stopifnot() also is a helpful command here.
Returning values: The value returned by the function is usually the last statement it evaluates, but you can choose to return early by using return(). It is better to save the use of return() to signal that you can return early with a simpler solution.
Some minor points
Using …, we can pass any number of arguments to a function.
Arguments in R are lazily evaluated: they’re not computed until they’re needed. That means if they’re never used, they’re never called.
R uses rules called lexical scoping to find the value associated with a name. That says if a value is not defined within a function, R uses its last definition, if possible.