Ruby Block Scope

Ruby makes good use of anonymous functions (code blocks) which the calling functions yield arguments to:

1.upto(3) do |n|
  puts(n)
end

# outputs:

1
2
3

Under the hood, the upto method is looping from 1 to 3, and on each loop it yields the index to the associated code block (anonymous function). The value yielded to the block is received in the n argument, which is local to the code block. To demonstrate that, let’s modify n in the code block:

1.upto(3) do |n|
  n *= 5
  puts(n)
end

# this line will generate an error
puts(n)

# outputs:

5
10
15

undefined local variable or method `n' 

As we can see, changing n within the block only affects the block, and n does not exist outside of the block. We can define variables within our block but they also are constrained to the block scope. Here we introduce the local variable name:

1.upto(3) do |n|
  name = "fred #{n}"
  puts(name)
end

# this line will generate an error
puts(name)

# outputs:

fred 1
fred 2
fred 3

undefined local variable or method `name'

As expected name is not accessible outside the block. It is possible to use and modify a variable declared outside the block:

name = 'tom'

1.upto(3) do |n|
  name = "fred #{n}"
  puts(name)
end

puts("name is now #{name}")

# outputs:

fred 1
fred 2
fred 3

name is now fred 3

What if we just want to use the same variable name, but not change the value of the outer scope? In this case, we can declare the variable in our block argument list:

name = 'tom'

1.upto(3) do |n, name|
  name = "fred #{n}"
  puts(name)
end

puts("name is now #{name}")

# outputs:

fred 1
fred 2
fred 3

name is now tom

The variable name in the outer scope is now unaffected by changes in the code block, and our block looks readable using the appropriately named local variable.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s