Closures & Function Factories

A closure is a function that carries with it the environment in which it was created, letting it remember and even update variables from that enclosing scope long after the outer function has returned.

Learn Closures & Function Factories in our free R course — a beginner-friendly interactive lesson with worked examples, a practice exercise and a quick…

Part of the free R course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.

By the end of this lesson you'll write function factories that build specialized functions, understand why each closure has private state, and use the super-assignment operator to persist that state between calls.

What You'll Learn in This Lesson

1️⃣ Functions That Return Functions

A function factory is a function whose return value is itself a function. The inner function captures the factory's arguments, so calling the factory with different values stamps out different specialized functions — here, a double and a triple from one make_multiplier .

2️⃣ Closures and Private State

The returned function plus its captured environment is a closure . Each closure holds its own copy of the captured variables, so hi and howdy never interfere with each other even though they came from the same factory.

3️⃣ Persisting State with <<-

To make a closure that changes its captured state between calls, use the super-assignment operator <<- . A plain <- would create a fresh local variable each call; <<- reaches up to update the captured one, giving the closure memory.

Your turn. Fill in the # TODO blanks, run it, and compare with the expected output.

Write an accumulator that keeps a running total in its closure with <<- . Then prove a second accumulator has independent state — the heart of closures.

📋 Quick Reference — Closures

Practice quiz

What is a function factory in R?

  • A function with no arguments
  • A built-in package for functions
  • A function that returns another function
  • A vector of functions

Answer: A function that returns another function. A function factory returns a new, specialized function as its value.

What is a closure?

  • A function bundled with the environment it was created in
  • A loop that never ends
  • A way to close a file connection
  • A type of vector

Answer: A function bundled with the environment it was created in. A closure is a function plus its captured enclosing environment.

In make_multiplier <- function(factor) function(x) x * factor, what does double <- make_multiplier(2) capture?

  • x fixed at 2
  • nothing; factor stays free
  • the whole global environment only
  • factor fixed at 2

Answer: factor fixed at 2. The returned function captures factor = 2 from where it was created.

Why use <<- instead of <- to update captured state in a counter?

  • <<- is faster than <-
  • <<- updates the variable in the enclosing environment
  • <- cannot appear inside functions
  • <<- creates a new local variable

Answer: <<- updates the variable in the enclosing environment. Plain <- makes a new local; <<- reaches up to update the captured variable.

Two counters made from the same make_counter() factory...

  • Each have their own independent count
  • Share a single global count
  • Always error on the second call
  • Must use the same variable name

Answer: Each have their own independent count. Each call to the factory creates a fresh environment with its own state.

What does lexical scoping mean for closures?

  • Variables resolve based on where the function is called
  • All variables are global
  • Variables resolve based on where the function was defined
  • Functions cannot see outer variables

Answer: Variables resolve based on where the function was defined. R uses lexical scoping: lookup follows the definition site, not the call site.

What happens if a factory forgets to return the inner function?

  • R raises a syntax error
  • You get the last evaluated value, not a function
  • The inner function still runs automatically
  • The factory returns NULL always

Answer: You get the last evaluated value, not a function. The factory must make the inner function its last expression to return it.

What does count <<- count + 1 require to already exist?

  • A global named count2
  • An integer literal named count
  • The package methods loaded
  • A count variable in an enclosing environment

Answer: A count variable in an enclosing environment. <<- searches enclosing environments for count to update it.

After double <- make_multiplier(2), what does double(7) return?

  • 9
  • 14
  • 2
  • 7

Answer: 14. double multiplies its argument by the captured factor 2, so 7 * 2 = 14.

Which call inspects the variables captured by a closure named add5?

  • names(add5)
  • str(add5())
  • ls(environment(add5))
  • environmentName(add5)

Answer: ls(environment(add5)). ls(environment(add5)) lists the names bound in the closure's environment.