1. Technology
Send to a Friend via Email
You can opt-out at any time. Please refer to our privacy policy for contact information.

Variables Declared in the Global Scope

By

Variables Declared in the Global Scope

Question

I declared a variable in the global scope, but I cannot access it from a method.


#!/usr/bin/env ruby

data = { :key => 'value' }

def print_hash
	puts data.inpsect
end

print_hash()

Answer

That is not a global variable. This is a misconception brought over from programmers familiar with (among other languages) C and C++. In C and C++, any variables declared at the file level are said to be in the "file scope," and can be accessed by any functions inside the same file, or in another file if the compiler is told the variable exists elsewhere using the extern keyword. But this is not the same in Ruby.

Ruby does not compute variable scope in quite the same way. Any variable without decoration (such as the at sign or dollar sign) is considered a local variable. Even if you declare the variable at the "file scope," it's still a local variable? Local to what? Local to a (usually) invisible object called main. You can access variables stored here from the "file scope," but in general, cannot access them from any other scope.

The problem here is that you've given Ruby no context. Ruby is not terribly comfortable with things like "file scope," and in anything larger than a 50 line script, it's best to abandon such notions. Be absolutely clear what you want to be able to access. So, to revise your question, perhaps you wished to ask "How can methods share a variable?"

One way to do this is to use a module. A module is used to encapsulate related methods and variables without the overhead and implications of a class. They can also be used for things like mixins, but they can be used just by themselves to allow variables to be shared among methods. In the following example, a module implemented the fixes the problem with the above example.


#!/usr/bin/env ruby

module DataPrinter
	@data = { :key => 'value' }

	def self.print_data
		puts @data
	end
end

DataPrinter.print_dat

As you can see, instead of using a "naked" variable, the at sign (the variable decoration to denote an instance variable) is used. This is now an "instance variable of the module." If you were going to include this module in a class or do anything like that, this has some implications. However, since the only thing that accesses it is the class method (note the self in the method definition) and the module is used as is, it's not worth worrying about. And, to print the data you'll need to specify the name of the module along with the method name.

Bonus Question

I declared a variable in the global scope, but I cannot access it from a method.


#!/usr/bin/env ruby

hash = { :key => 'value' }

def print_hash
	puts hash.inpsect
end

print_hash()

Bonus Answer

This looks like the same question, right? Look at the hash variable name. Instead of data, it's called hash. Seems like a trivial change, but it completely changes the error message. Instead of a missing variable error message, you get an error message complaining that a Fixnum object doesn't have an inspect method. Or, instead of a hash you may simply get a number. What's happening here?

All objects have a hash method. This method generates a number that's used in hash objects to sort them into hash buckets. You can assign a value to the local variable hash, then the naked word hash refers to the variable. To access the main object's hash method, explicitly call the method using parentheses with hash() and Ruby will look through the method list, instead of the local variable list.


puts hash  # A large number

hash = 10
puts hash  # Prints 10

puts hash()  # Prints the large number

So, what's happening here is the same thing that's happening in the first example. Inside the method there's no variable called hash, but it's getting the hash value of another object, possibly the binding from inside the method, and it produces a very confusing situation. This just goes to show that, given Ruby's flexible syntax, error messages can be very misleading. Ruby has no idea the word hash is supposed to be a variable and not a method call. It will check the local variables first and, if it doesn't find a variable, check for a method. Always be aware of that, and be aware that there are a number of methods available in any given scope that can be called accidentally.

  1. About.com
  2. Technology
  3. Ruby
  4. Question and Answer
  5. Variables Declared in the Global Scope

©2014 About.com. All rights reserved.