The environment is the data structure that powers scoping. This chapter dives deep into environments, describing their structure in depth, and using them to improve your understanding of the four scoping rules described in Section 6.4. Understanding environments is not necessary for day-to-day use of R. But they are important to understand because they power many important R features like lexical scoping, namespaces, and R6 classes, and interact with evaluation to give you powerful tools for making domain specific languages, like dplyr and ggplot2.
If you can answer the following questions correctly, you already know the most important topics in this chapter. You can find the answers at the end of the chapter in Section 7.7.
List at least three ways that an environment differs from a list.
What is the parent of the global environment? What is the only environment that doesn’t have a parent?
What is the enclosing environment of a function? Why is it important?
How do you determine the environment from which a function was called?
Section 7.2 introduces you to the basic properties of an environment and shows you how to create your own.
Section 7.3 provides a function template for computing with environments, illustrating the idea with a useful function.
Section 7.4 describes environments used for special purposes: for packages, within functions, for namespaces, and for function execution.
Section 7.5 explains the last important environment: the caller environment. This requires you to learn about the call stack, that describes how a function was called. You’ll have seen the call stack if you’ve ever called
traceback()to aid debugging.
Section 7.6 briefly discusses three places where environments are useful data structures for solving other problems.
This chapter will use rlang functions for working with environments, because it allows us to focus on the essence of environments, rather than the incidental details.
env_ functions in rlang are designed to work with the pipe: all take an environment as the first argument, and many also return an environment. I won’t use the pipe in this chapter in the interest of keeping the code as simple as possible, but you should consider it for your own code.