Local Variables and Scoping Rules

One of the most fundamental knowledge in programming is understanding how to assess variables in the code. This concept is a cornerstone to the act of ‘coding with intention’ and mastering any programming language.

At the beginning of our journey, we are mostly focused on playing with code, exploring its limits and if it happens to achieve the needed task, then it is ‘good enough’.

As we begin to program we might tend to immediately reach out to a global variable only because it is accessible everywhere in the code. Also, doing so does not require an understanding of how a variable works. It can be an easy means of solving a problem. However, as we progress in our journey to learn to program we will require more sophisticated ways of solving problems. That is when in-depth knowledge on how variables operate will come in handy.

In this text, I will be focusing on Local Variables and the examples I will use here are written in Howeverthe basic concept is fundamental to any programming language. Local Variables are a type of variable that is bound to all , making it a good starting place for people who are on a learning journey to software programming.

What is a variable?

A variable is a“pointer” to an object. This object is a storage location (in computer memory) paired with an associated value.

Variables act as pointers to objects.

It might be useful to think of variables as labels to refer to physical spaces in your computer memory. These memory spaces can hold different values and these labels can take almost any name, but it is important to choose descriptive names that will be unmistakably understood by whoever reads your code.

A variable label or name can be used to access and manipulate an object throughout a program. However, questions such as when or where this object can be accessed will depend on each variable scoping rule. There are five different types of variable — each with their own accessibility constraints, more or less appropriate for different purposes.

Types of Variable

There is a lot of material available on the about this subject. I have chosen to refer to Types of Variables from Launch School because they provide simple examples and clear descriptions. Below is a summary of what each variable is and how they look like:

Variable assignment

Before we go any further, let’s talk about a few key concepts: variable definition, referencing, initialisation, assignment and reassignment.

It can be helpful to think of variable assignment as a way of labelling data you manipulate in your program.

The act of assigning a value to a variable is done by using the symbol =. What is on the left of the sign = is the variable and what is on the right represents the value assigned to this variable. A value can be of any data type: string, integer, array, hash, boolean, symbol. In the example below the variable author_name the string object 'Raquel Nishimoto'.

first_example.rb — Variable assignment and variable reassignment.

A variable is when we assign a value to it for the first time. At line number 3, author_name is initialised by the string object 'Raquel Nishimoto' to the local variable author_name.

author_name is initialised by assigning the string object 'Raquel Nishimoto' to the local variable author_name.

At line number 4, the local variable writer is initialised by that same string object that the local variable author_name references to. Now, they are pointing to the same object or same space in memory.

Local variable ‘author_name’ and ‘writer’ are pointing to the same object or same space in memory.

Note that both local variables have the same object_id 70133050072720, which represents the same space in memory.

Local variable ‘author_name’ and ‘writer’ have the same object_id 70133050072720

Reassignment

In at line number 5, the local_variable author_name is a string object with a different value 'Virginia Woolf'. Now, author_name references a different string object with a different value.

Reassignment of the local variable

Note that the reassignment of the local variable changed the object id from 70133050072720 to 70133050065240. Now, they point to different spaces in memory.

Example of reassignment.

Local variable ‘author_name’ and ‘writer’ point to different spaces in memory.

Local Variable Scoping Rule

A variable’s scope determines the accessibility of a variable — whether a variable will be accessed or not from a certain location. What drives this scope is:

In , a block is a piece code that follows a method invocation — it is encircled by {} if it is an inline-block or do (…) end if it is a multiline-block.

Inline block — code that is arranged in a line:

Inline block — #each followed by {}

Multiline block — code that is NOT arranged inline.

Multiline block — #each followed by do…end.

A block marks the boundaries of variable scope:

Scoping Rule: Inner scope can access variables initialized in an outer scope, but not vice versa.

second_example.rb — the local variable is initialised outside of a block.

For example, in the

The local variable ‘sum’ is initialised outside of the block.

sum is accessible in the inner scope of this block. sum is a new value every time it iterates through the loop (at lines 5–7). At line 9, we are calling puts method (part of Kernel module) and passing the local variable sum as its argument.

After running the value printed on the screen will be 18. The reason is:

Local variables can be changed (in this case by reassignment) from an and this change carry on to the outer scope.

However, in (below)the local variable total is initialised inside the inner scope and we try to access it in the outer scope.

third_example.rb — local variable total is initialised inside the inner scope

As we already mentioned, sum is initialised in the outer scope and therefore is accessible in the inner scope. Any reassignments (at line 6) are carried on to the outer scope. Therefore, the code will output 18.

However, this program will also raise an exception: . The error tells us the local variable totalinitialised in the inner scope (inside the block at line 7) be accessed in the outer scope. At line 11, we are calling puts method and passing the local variable total as its argument — however, total is not accessible from there (outer scope).

We now know that a block creates a new scope for local variables. However, not all chunks of code delimited by do (…) end are blocks. For example:

Not all chunks of code delimited by do (…) end are blocks.

The answer to whether the local variable total is accessible there is yes. The reason is that in this case, do (…) end does not constitute a block - note that for (…) in are keywords. Therefore, they will not create a new scope (or boundary) for the numbersvariable. Remember,

How about ‘nested blocks’? Nested blocks are bound to all scoping rules and work under the same principle as an individual block would. However, they have some additional complexity. This is because every time a block is added inside an existing block, this new block will create a new inner scope.

fourth_example.rb — nested blocks.

The code from will output the following:

fourth_example.rb — output.

This demonstrates that will conform to local variables rule as well. Local variables will not be accessed from when initiatised in . At line 21, the local variableplayer_score is not accessible anymore. The definition of inner and outer scope will be relative from the location where the variable is being referenced.

Another important concept about local variables is

In if the nested block was split into two ‘loop (…) do’ blocks, each would have their own individual scope and would not access each other’s inner variables.

fifth_example.rb — peer blocks have their own inner scope.

Running this program will output 1, but it would also throw errors whenever the local variable is referenced in peer blocks (line 9) and in the outer scope as well (line 13). This is because each block has its own scope.

Variable shadowing

Going a little deeper in our exploration, we stumble upon another key concept: . Variable shadowing refers to the practice of naming two variables — for example, a local variable and a method parameter, with the same name and within scopes that overlap. We mentioned earlier that local variables initialised in the outer scope of a block can be accessed in its inner scope. Well, not in this case.

Variable shadowing — variable with same names within scopes that overlap.

This short program will output 0; then 1 in a new line; and 2 in another line. It will not output 10. The second variable countdefined in the of the block will 'shadow' the variable initialised in the . The first variable countinitialised in the of the block will not be accessed in the block .

Variable shadowing will have two consequences:

Firstly, the local variable initialised outside of the block will be ignored or ‘hidden’ from the inner scope of a block. In this case, the higher-level variable is ‘shadowed’ and whenever that variable name is referenced inside the block, the lower-level variable in the block will take precedence and override that variable initialised in the outer scope.

Secondly, the outer scoped variable will remain unchanged. Any transformations and reassignments that occurs in the block will not reflect in any way the outer scoped variable.

The outer variable is ‘shadowed’ and therefore protected from any changes.

Variable shadowing — protects variables initialised in the outer scope from modifications done in the inner scope.

Remember that we mentioned that a variable in the can be accessed externally (to the block) only if it is initialised in the is the exception.

Methods and Local Variables

The relationship between methods and local variables can be summarised as the following:

Let’s break this down.

Firstly, a method definition does not determine as a block would do. It will only access local variables that are passed in as arguments.

Example of a method definition with no parameters.

Secondly, a method can only have access to the local variable language if it is defined with one parameter and called in with language as its argument.

Example of a method being defined with one parameter.

In other words, the string object ‘Ruby’ has to be passed into program as an argument, which will then assigned to the parameter lang. However, inside the method definition local variables, blocks and their scoping rules will operate under the principle already stated:

One important point to remember though is that if a variable is initialised outside the method definition, it will have to be passed in as an argument into the method. Otherwise, the method will have no access to it.

Summary

Local variables and its scoping rules are fundamental to programming. They involve a high level of abstraction which might not come naturally to most of us.

Until all these concepts become part of our , it can be useful to break down each idea, making them explicit with examples and building along this process a mental model of how it all fits together. Another way of internalising this knowledge is to practice. You might not get it completely the first time, but try to practice, do exercises and revisit these concepts in spaced periods of time.

Understanding local variables and its scoping rules is worthwhile. Firstly, because it can be transferable to any programming language. Secondly, because knowing how to manipulate variables is at the core of any program you will write.

Software Engineer in tireless pursuit of improving my craft and in a journey to learn by sharing with the community.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store