π R Environments & Scoping: The House of Variables
Imagine your R program is a big house with many rooms. Each room can hold things (variables), and there are special rules about who can see what!
π The Global Environment: Your Living Room
Think of the Global Environment as your living room β itβs the main room everyone can see.
When you create a variable in R without being inside a function, it goes straight to the living room!
# This goes in the living room (Global)
my_toy <- "teddy bear"
# Check what's in the living room
ls()
# [1] "my_toy"
π Key Facts:
- Everything you type in R console lives here
- All rooms in your house can peek into the living room
- Use
ls()to see whatβs in the living room - Use
rm(my_toy)to throw something away
graph TD A["π Global Environment"] --> B["my_toy = teddy bear"] A --> C["my_name = Alice"] A --> D["my_age = 10"]
πͺ The Local Environment: Your Private Bedroom
When you create a function, it gets its own bedroom β a private space!
my_function <- function() {
# This toy is ONLY in this bedroom
secret_toy <- "robot"
print(secret_toy)
}
my_function()
# [1] "robot"
# Try to find it in living room?
print(secret_toy)
# Error! It's hidden in the bedroom!
π― Simple Rule:
- Inside a function = Your private bedroom
- Outside a function = The living room
- Private bedroom toys disappear when you leave!
graph TD A["π Global Environment"] --> B["my_function"] B --> C["π¦ Local Environment"] C --> D["secret_toy = robot"] D --> E["ποΈ Gone when function ends!"]
π Variable Scoping: The Looking Rules
Scoping is like the rule: βYou can look OUT of your room, but others canβt look IN.β
living_room_toy <- "ball" # In the living room
play <- function() {
# Can I see the living room toy? YES!
print(living_room_toy)
bedroom_toy <- "puzzle" # My private toy
print(bedroom_toy)
}
play()
# [1] "ball" <- Found in living room!
# [1] "puzzle" <- Found in bedroom!
# Can living room see bedroom toy? NO!
print(bedroom_toy)
# Error: object 'bedroom_toy' not found
πͺ The Looking Order:
graph TD A["π Looking for a toy?"] --> B{Check my room first} B -->|Found!| C["β Use it!"] B -->|Not found| D{Check living room} D -->|Found!| C D -->|Not found| E{Check R's built-in room} E -->|Found!| C E -->|Not found| F["β Error: Not found!"]
π οΈ Environment Manipulation: Moving Things Around
You can actually peek into any room and move things if you know how!
See Whatβs in a Room:
# What's in my living room?
ls(envir = globalenv())
# Create a new room (environment)
my_box <- new.env()
# Put a toy in the box
my_box$hidden_gem <- "diamond"
# Peek inside the box
ls(envir = my_box)
# [1] "hidden_gem"
# Grab the toy
get("hidden_gem", envir = my_box)
# [1] "diamond"
Useful Commands:
| Command | What It Does |
|---|---|
new.env() |
Make a new box |
ls(envir = x) |
Look inside box x |
get("name", envir = x) |
Grab item from box |
assign("name", value, envir = x) |
Put item in box |
exists("name", envir = x) |
Is this item in box? |
π Closures: Functions That Remember
A closure is like giving someone a backpack with stuff inside. Even when they leave, they keep their backpack!
make_counter <- function() {
count <- 0 # Put this in the backpack!
function() {
# Use <<- to update backpack item
count <<- count + 1
print(count)
}
}
# Give someone a counter backpack
my_counter <- make_counter()
my_counter() # [1] 1
my_counter() # [1] 2
my_counter() # [1] 3
# It remembers!
# Make another counter - fresh backpack!
other_counter <- make_counter()
other_counter() # [1] 1
# Starts fresh!
π Why This Works:
graph TD A["make_counter runs"] --> B["Creates count = 0"] B --> C["Returns inner function"] C --> D["Inner function keeps<br>count in its backpack!"] D --> E["Each call updates<br>its own count"]
The inner function closes over the count variable β it carries it forever!
π Lexical Scoping: Where You Were Born Matters
Lexical scoping means: βA function looks for variables where it was CREATED, not where itβs CALLED.β
Think of it like this: You always know your home address, even if youβre visiting somewhere else!
x <- "living room" # Global
outer_function <- function() {
x <- "bedroom" # Local to outer
inner_function <- function() {
print(x) # Which x?
}
inner_function()
}
outer_function()
# [1] "bedroom"
# inner_function was BORN in bedroom,
# so it looks there first!
π Another Example:
home_value <- 100
# This function was born in global
get_value <- function() {
return(home_value)
}
test <- function() {
home_value <- 999 # Different local value
get_value() # What does it return?
}
test()
# [1] 100
# NOT 999! Because get_value looks at
# where it was BORN (global), not
# where it was CALLED (inside test)
graph TD A["π Global: home_value = 100"] --> B["get_value born here"] A --> C["test function"] C --> D["home_value = 999 locally"] D --> E["Calls get_value"] E --> F["get_value looks at birthplace"] F --> G["Returns 100 from Global!"]
π― Quick Summary
| Concept | Simple Explanation |
|---|---|
| Global Environment | The living room everyone can see |
| Local Environment | Private bedroom inside a function |
| Variable Scoping | Look in your room first, then living room |
| Environment Manipulation | Moving toys between rooms |
| Closures | Functions with backpacks that remember |
| Lexical Scoping | Functions look where they were born |
π You Did It!
Now you understand how R organizes its variables like rooms in a house!
Remember:
- π Global = Living room (everyone sees it)
- πͺ Local = Private bedroom (hidden away)
- π Scoping = Looking rules (inside β outside)
- π Closures = Backpacks that remember
- π Lexical = Birthplace matters!
Go play with environments in R β create some rooms, hide some toys, and watch the magic happen! β¨
