Zamplized Ruby User's Guide

Local variables

A local variable has a name starting with a lower case letter or an underscore character (_). Unlike globals and instance variables, local variables do not have the value nil before initialization:

ruby> $foo    nil ruby> @foo    nil ruby> foo ERR: (eval):1: undefined local variable or method `foo' for main(Object)

The first assignment you make to a local variable acts something like a declaration. If you refer to an uninitialized local variable, the ruby interpreter cannot be sure whether you are referencing a bogus variable or calling a nonexistent method; hence the error message you see above.

Generally, the scope of a local variable is one of

In the next example, defined? is an operator which checks whether an identifier is defined. It returns a description of the identifier if it is defined, or nil otherwise. As you see, bar's scope is local to the loop; when the loop exits, bar is undefined. This example also shows how semicolons can be used to separate multiple ruby program statements on one line.

foo = 44; puts foo; defined?(foo)
loop {bar=45; puts bar; break}; defined?(bar)

Output

ruby> foo = 44; puts foo; defined?(foo)
44
   "local-variable"
ruby> loop {bar=45; puts bar; break}; defined?(bar)
45
   nil

Procedure scoped objects scope share local variables of the parent scope. In the following example, the local variable bar is defined by main and is referenced by the procedure objects p1 and p2:

bar = nil
p1 = proc {|n| bar=n}
p2 = proc {bar}
p1.call(5)
bar
p2.call

Output

ruby> bar = nil
   nil
ruby> p1 = proc {|n| bar=n}
   #<Proc:0xb7d6b400@(eval):1>
ruby> p2 = proc {bar}
   #<Proc:0xb7d6b20c@(eval):1>
ruby> p1.call(5)
   5
ruby> bar
   5
ruby> p2.call
   5

Note that the "bar=nil" at the beginning cannot be omitted; it ensures that the scope of bar will encompass p1 and p2. Otherwise p1 and p2 would each end up with its own local variable bar, and calling p2 would have resulted in an "undefined local variable or method" error. We could have said bar=0 instead, but using nil is a courtesy to others who will read your code later. It indicates fairly clearly that you are only establishing scope, because the value being assigned is not intended to be meaningful.

A powerful feature of procedure objects follows from their ability to be passed as arguments: shared local variables remain valid even when they are passed out of the original scope. The next code example also shows how to return more than one result from a method (similar to Python). In this example, contents is an instance variable.

def box
   contents = nil
   get = proc{contents}
   set = proc{|n| contents = n}
   return get, set
end

reader, writer = box
reader.call
writer.call(2)
reader.call

Abbreviated Output

ruby> reader, writer = box
   [#<Proc:0xb7d2739c@(eval):3>, #]
ruby> reader.call
   nil
ruby> writer.call(2)
   2
ruby> reader.call
   2

It is evident in our example that the instance variable contents is shared between reader and writer. We can manufacture multiple reader-writer pairs using box as defined above; each pair shares their own private contents instance variable, so the pairs do not interfere with each other.

def box
   contents = nil
   get = proc{contents}
   set = proc{|n| contents = n}
   return get, set
end

reader_1, writer_1 = box
reader_2, writer_2 = box
writer_1.call(99)
reader_1.call
reader_2.call  # nothing is in this box yet

Abbreviated Output

ruby> reader_1, writer_1 = box
   [#<Proc:0xb7cf739c@(eval):3>, #]
ruby> reader_2, writer_2 = box
   [#<Proc:0xb7cf739c@(eval):3>, #]
ruby> writer_1.call(99)
   99
ruby> reader_1.call
   99
ruby> reader_2.call  # nothing is in this box yet
   nil

This kind of programming could be considered a perverse little object-oriented framework. The box method acts something like a class, with get and set serving as methods (except those aren't really the method names, which could vary with each box instance) and contents being the lone instance variable. Of course, using ruby's legitimate class framework leads to much more readable code.

Copyright (c) 2005 Mark Slagell

Portions copyright (c) 2005 Zamples, Inc.

Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.

A copy of the license is included in the section entitled "GNU Free Documentation License."