Chapter 27 Accessibility of variables
It is essential to always keep in mind where your variables are, and whether they are defined and accessible:
Variables defined inside a function are not accessible outside from it!
Variables defined outside a function are accessible inside, and are not modified, even if they have the same name.
<- 3
out_val <- function() {
vartest <- 4
in_val print(in_val)
print(out_val)
}vartest()
## [1] 4
## [1] 3
in_val
## Error in eval(expr, envir, enclos): object 'in_val' not found
out_val
## [1] 3
out_val_2
## Error in eval(expr, envir, enclos): object 'out_val_2' not found
What happens in the function club, stays in the function club.
Be very careful when creating variables inside a conditional statement as the variable may never have been created and cause (sometimes unperceptible) errors.
<- 3
var1 <- function() {
vartest <- 4 # 'a' is defined inside
a print(a) # print 'a'
print(var1) # print var1
}# we cannot print 'a' as it exists only inside the function a
## [1] 19.96041
vartest() # calling vartest() will print a and var1
## [1] 4
## [1] 3
rm(var1) # remove var1
vartest() # calling the function again does not work anymore
## [1] 4
## Error in vartest(): object 'var1' not found
Tip It is good practice to define variables outside the conditions and then modify their values to avoid any problems.
<- 3
a if (a > 5) {
<- 2
b
}+ b a
If you had b
already assigned in your environment, with a different
value, you could have had a bigger problem!
# Error: object 'b' not found
27.1 Why should I care about programming practices?
- It makes your life easier;
- It helps you achieve greater readability and makes sharing and reusing your code a lot less painful;
- It helps reduce the time you will spend remembering and understanding your own code.
Keep a clean and nice code
Proper indentation and spacing is the first step to get an easy to read
code:
- Use spaces between and after you operators
x>=1&x<=10
is more difficult to read then x >= 1 & x <= 10
- Use consistently the same assignation operator.
<- is often preferred. = is OK, but do not switch all the time between the two
Use brackets when using flow control statements:
- Inside brackets, indent by at least two spaces;
- Put closing brackets on a separate line, except when preceding an
else
statement.
Define each variable on its own line.
Use
Cmd + I
orCtrl + I
in RStudio to indent the highlighted code automatically;
if ((a[x, y] > 1) & (a[x, y] < 2)) {
print("Between 1 and 2")
}
if ((a[x, y] > 1) & (a[x, y] < 2)) {
print("Between 1 and 2")
}
This code is not spaced, and therefore hard to read. All brackets are badly aligned, and it looks “messy”.
<- 4
a = 3
b if (a < b) {
if (a == 0)
print("a zero")
else {
} if (b == 0) {
print("b zero")
else print(b)
} }
On the left, code is not spaced, nor indented. All brackets are in the same line, and it looks “messy”. On the right, it looks more organized, no?
<- 4
a <- 3
b if (a < b) {
if (a == 0) {
print("a zero")
}else {
} if (b == 0) {
print("b zero")
else {
} print(b)
} }
27.2 Use functions to simplify your code
Write your own function: 1. When portion of the code is repeated more than a few times in your script; 2. If only a part of the code changes and includes options for different arguments.
This would also reduce the number of potential errors done by copy-pasting, and the time needed to correct them.
Let’s modify the example from Challenge 3 and suppose that all \(CO_2\) uptake from Mississipi plants was overestimated by 20 and Quebec underestimated by 50.
We could write this:
for (i in 1:length(CO2[, 1])) {
if (CO2$Type[i] == "Mississippi") {
$conc[i] <- CO2$conc[i] - 20
CO2
}
}for (i in 1:length(CO2[, 1])) {
if (CO2$Type[i] == "Quebec") {
$conc[i] <- CO2$conc[i] + 50
CO2
} }
Or this:
<- function(CO2, type, bias) {
recalibrate for (i in 1:nrow(CO2)) {
if (CO2$Type[i] == type) {
$conc[i] <- CO2$conc[i] + bias
CO2
}
}return(CO2)
}
<- recalibrate(CO2 = CO2, type = "Mississipi", bias = -20)
newCO2 <- recalibrate(newCO2, "Quebec", +50) newCO2
27.3 Use meaningful names for functions
Same function as before, but with vague names:
<- function(c, t, b) {
rc for (i in 1:nrow(c)) {
if (c$Type[i] == t) {
$uptake[i] <- c$uptake[i] + b
c
}
}return(c)
}
Whenever possible, avoid using names of existing R
functions and variables to avoid confusion and conflits.
27.4 Use comments: #
.alert[Final tip]. Add comments to describe what your code does, how to use its arguments or a detailed step-by-step description of the function.
# Recalibrates the CO2 dataset by modifying the CO2 uptake
# concentration by a fixed amount depending on the region
# of sampling. Arguments CO2: the CO2 dataset type: the
# type ('Mississippi' or 'Quebec') that need to be
# recalibrated bias: the amount to add or remove to the
# concentration uptake
<- function(CO2, type, bias) {
recalibrate for (i in 1:nrow(CO2)) {
if (CO2$Type[i] == type) {
$uptake[i] <- CO2$uptake[i] + bias
CO2
}
}return(CO2)
}
Challenge 6: Group exercise
Using what you learned, write an if()
statement that tests whether a numeric variable x
is 0
. If not, it assigns \(cos(x)/x\) to z
, otherwise it assigns \(1\) to z
.
Create a function called my_function()
that takes the variable x
as argument and returns z
.
If we assign \(45\), \(20\), and \(0\) to x
respectively, which of the following options would represent the results?
1. \(0.054\), \(0.012\), and \(0\);
2. \(0.020\), \(0.054\), and \(1\);
3. \(0.012\), \(0.020\), and \(1\).
In addition to this, discuss with your group about a function that you would like to create (it can or it may not be related to your research). Be prepared to briefly describe it to us!
???
This exercise should take place in breakout rooms within 10 minutes. After rejoining the main room, a poll should be opened to participants. Once you obtain the response from participants, show them the correct answer and code. You may request that one of the participants explain their answer before showing the results.