Functions Have (Almost) No Side Effects
What is a Side Effect?
A side effect occurs when a function modifies something outside its scope or environment. This could include:
- Changing global variables.
- Writing to or reading from files.
- Altering objects in external environments.
Ideal Behavior of Functions
Good programming practices suggest that functions should:
- Be Pure: Functions should return results based solely on their input arguments and not modify the global environment or their inputs.
- Avoid Side Effects: A pure function does not alter variables or objects outside of its local scope.
Example of a Pure Function
# Pure function add_numbers <- function(a, b) { return(a + b) } # Call the function result <- add_numbers(5, 3) print(result) # Prints 8
In this example, add_numbers is a pure function. It takes arguments, performs an operation, and returns a result without modifying other variables or objects.
Example of a Function with Side Effects
# Global variable global_var <- 10 # Function with a side effect modify_global <- function() { global_var <<- 20 # Modifies the global variable } # Call the function modify_global() print(global_var) # Prints 20
Here, modify_global changes global_var, which is a side effect.
Using Local Variables
Functions should ideally use local variables to avoid side effects. Local variables are created and accessed only within the function.
# Function with local variables calculate_square <- function(x) { local_var <- x^2 return(local_var) } # Call the function square <- calculate_square(4) print(square) # Prints 16
In this case, local_var is local to calculate_square and does not affect the global environment.
Managing Side Effects in Functions
Sometimes, introducing side effects is intentional, such as modifying an object in a specific environment or saving data to a file. Here’s how to handle them:
Using <<- to Modify Global Variables
Though generally discouraged, <<- can be used to modify global variables.
# Function modifying a global variable update_global <- function(value) { global_var <<- value } # Call the function update_global(50) print(global_var) # Prints 50
Using assign() to Modify Variables
The assign() function can modify variables in specific environments.
# Create a new environment my_env <- new.env() # Function modifying a variable in a specific environment update_env <- function(value) { assign("my_var", value, envir = my_env) } # Call the function update_env(100) print(my_env$my_var) # Prints 100
Summary
- Pure Functions: A pure function returns a value without side effects.
- Avoiding Side Effects: Functions should avoid modifying the global state or relying on side effects.
- Controlled Management: When necessary, side effects should be managed carefully and intentionally.