51

I'm new to programming. Right now I'm studying Ruby. To my understanding, global variables are defined in the global namespace (so outside of any classes or functions). I'm reading something and it says global variables have a $ sign before them. What does that mean? Does it mean when I define a function or class and want to reference my global variable (let's say it is edmund = 123) I would have to reference it like this: $edmund?

so:

edmund = 123
def my_function()
  456 + $edmund
end

Also are class variables (the ones that begin with @@) like instance variables (@) where you can access them by calling them through Class.classvariable? What is their purpose?

3
  • Oh. So when I define the variable it's $edmund. but what about calling it (as I do in my_function())? I no longer have to use the $ sign anymore right? Commented Aug 24, 2012 at 16:22
  • Yes, you have ; the dollar sign is part of the variable name. Commented Aug 24, 2012 at 16:26
  • possible duplicate of in Ruby, how to use global variables or constant values? Commented Aug 24, 2012 at 16:48

3 Answers 3

56

Global scope is scope that covers the entire program. Global scope is enjoyed by global variables, which are recognizable by their initial dollar-sign ($) character. They’re available everywhere and creating your own global variables can be tempting, especially for beginning programmers. But they’re not always a good idea.

$gvar = "I'm a global!"
class C
    def examine_global
        puts $gvar
    end
end

c = C.new
c.examine_global # I'm a global!

Class variables begin with two at signs: @@var, for example. Despite their name, class variables aren’t class scoped. Rather, they’re class-hierarchy scoped. At its simplest, the idea behind a class variable is that it provides a storage mechanism that’s shared between a class and instances of that class, and that’s not visible to any other objects.

class Parent
    @@value = 100
end

class Child < Parent
    @@value = 200
end

class Parent
    puts @@value
end

What gets printed is 200. The Child class is a subclass of Parent, and that means Parent and Child share the same class variables—not different class variables with the same names, but the same actual variables. When you assign to @@value in Child, you’re setting the one and only @@value variable that’s shared throughout the hierarchy— that is, by Parent and Child and any other descendant classes of either of them.


And to give credit where its due - This explanation comes from "The Well Grounded Rubyist" by David A Black, one of the best resources to learn about Ruby.

Sign up to request clarification or add additional context in comments.

4 Comments

Is there a way to reference a class variable directly (without calling a mthod) such as from irb. And if so, what is the syntax? clasname.@@var doesnt work
If you know your class variable you could do Clasname.class_variable_get(:@@var). And if you want to access all class variables Clasname.class_variables.each {|v| p Clasname.class_variable_get(v)}
Great answer but small nitpick: class variables aren’t class scoped - class variables aren't instance scoped.
@JamesKingsbery Of course, they aren't instance scoped, but that wasn't the point. The point was that the scope of a class variable is not the class, but the complete class hierarchy (depite the name). No reason for nitpicking...
12

Excellent question. Unfortunately, you just jumped down a rabbit hole, but it's one that you have to fall through eventually in ruby to start understanding the real intricacies.

For your first question, regarding the $-prefixed global variables. They are truly global:

def mk_foo() $foo ||= "foo"; end

$foo                # => nil
mk_foo              # => "foo"
$foo                # => "foo"
mk_foo.object_id    # => 70299647799620
$foo.object_id      # => 70299647799620

As you can see, when $foo is defined within the mk_foo method, it is defined in the global space, and you can access it anywhere:

class CanSeeFoo
  def see_foo() $foo; end
end
CanSeeFoo.new.can_see_foo
# => "foo"
CanSeeFoo.new.can_see_foo.object_id
# => 70299647799620

As for the class variable question, this is where the rabbit-hole begins. First, you are correct that @@-prefixed variables are referred to as "class variables" and @-prefixed variables are referred to as "instance variables".

Class variables are static across all subclasses (at all sub-levels of the inheritance tree) of the defining class. The implication here is that if any subclass changes the class variable, it will change in all related subclasses and up to the defining class.

class A; end
class B < A; @@foo = "foo";  end
B.class_variable_get(:@@foo)    # => "foo"
A.class_variable_get(:@@foo)
  # => raises NameError "uninitialized class variable @@foo in A"

class C < B; end
C.class_variable_get(:@@foo)    # => "foo"

class D < C
  def self.change_foo(); @@foo = "bar"; end
  def change_foo(); @@foo = "baz"; end
end
D.class_variable_get(:@@foo)    # => "foo"

class E < D; end
E.class_variable_get(:@@foo)    # => "foo"

D.change_foo                    # => "bar"
D.class_variable_get(:@@foo)    # => "bar"
E.class_variable_get(:@@foo)    # => "bar"
C.class_variable_get(:@@foo)    # => "bar"
B.class_variable_get(:@@foo)    # => "bar"

D.new.change_foo                # => "baz"
D.class_variable_get(:@@foo)    # => "baz"
E.class_variable_get(:@@foo)    # => "baz"
C.class_variable_get(:@@foo)    # => "baz"
B.class_variable_get(:@@foo)    # => "baz"
A.class_variable_get(:@@foo)
  # => raises NameError "uninitialized class variable @@foo in A"

As for accessing class and instance variables, neither is accessible without the use of #instance_variable_get or ::class_variable_get until an accessor is defined. At present, ruby only has methods for defining accessors on instance variables, but it is simple enough to define the appropriate methods for the class variables:

class A
  @@foo = "foo"

  # the second argument `true` adds the writer method `#bar=`
  attr :bar, true

  def self.foo(); @@foo; end
  def self.foo=(v); @@foo = v; end

  def initialize()
    @bar = "bar"
  end
end
class B < A; end

A.foo             # => "foo"
B.foo = "foobar"
A.foo             # => "foobar"
B.foo             # => "foobar"

a = A.new
a.bar             # => "bar"
a.bar = "baz"
a.bar             # => "baz"

a.foo
  # => raises NoMethodError: undefined method `foo' for #<A:0x ...

You can see the attribute accessor methods here in the ruby core docs: http://www.ruby-doc.org/core-1.9.3/Module.html#method-i-attr. Also, ActiveSupport (http://rubygems.org/gems/activesupport) has "cattr" methods for defining class variable accessors http://api.rubyonrails.org/v3.2.5/classes/Class.html#method-i-cattr_accessor.

That's the simple stuff. The next step is understanding the "singleton class" also known as the "eigenclass" or "metaclass" (Wikipedia: Metaclass) (remember, everything in ruby is an Object, including the Class and Module constructs). Here I will point you to an excellent post by Yehuda Katz: Metaprogramming in Ruby: It’s All About the Self, and another Stack Overflow question: class << self idiom in Ruby.

As a preview: The singleton class (not to be confused with the singleton design pattern) allows you to access methods and instance data for a specific class or module. For some related documentation, see the core docs: http://www.ruby-doc.org/core-1.9.3/Object.html#method-i-singleton_class

class A; end
class B < A;
  class << self
    def foo() @foo end
    def foo=(v) @foo = v; end
  end
end
B.foo = "foo"

class C < B; end

A.foo
  # => raises NoMethodError: undefined method `foo' for A:Class

B.foo         # => "foo"
C.foo         # => nil
B.foo = "baz"
B.foo         # => "baz"
C.foo         # => nil
C.foo = "foo"
C.foo         # => "foo"
B.foo         # => "baz"

Lastly, remember to make use of the Ruby-Core docs. Most useful for understanding the above are:

Comments

5

The dollar sign is part of the variable name, so it has to be declared like this:

$edmund = 123

This is the same things for the instance and class variables: their names begin with @ or @@.

1 Comment

I like this answer best because it is just so short as it can be, but no shorter, while treating every question in original post.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.