Local variable scope

I’m a bit confused by the scope of local variables.

$ irb --simple-pompt

foo = “bar”
=> “bar”
def function
puts foo
end
=> nil
function
NameError: undefined local variable or method foo' for #<Object:0xf9000> from (irb):3:in function’
from (irb):5

Since ‘foo’ was defined before ‘function’ and both ‘function’ and ‘foo’
are in the same scope (I think) shouldn’t ‘function’ see ‘foo’?

···


Daniel Carrera
Graduate Teaching Assistant. Math Dept.
University of Maryland. (301) 405-5137

Hi,

···

At Tue, 21 Jan 2003 04:32:59 +0900, Daniel Carrera wrote:

$ irb --simple-pompt

foo = “bar”
=> “bar”
def function
puts foo
end
=> nil
function
NameError: undefined local variable or method foo' for #<Object:0xf9000> from (irb):3:in function’
from (irb):5

Since ‘foo’ was defined before ‘function’ and both ‘function’ and ‘foo’
are in the same scope (I think) shouldn’t ‘function’ see ‘foo’?

Any methods have each own scopes.


Nobu Nakada

Daniel Carrera wrote:

Since ‘foo’ was defined before ‘function’ and both ‘function’ and ‘foo’
are in the same scope (I think) shouldn’t ‘function’ see ‘foo’?

You can do this in 1.7:

module M
foo = “bar”
define_method :function do
puts foo
end
end
include M

function # prints: bar

In article 20030120193158.GA1029@math.umd.edu,

···

Daniel Carrera dcarrera@math.umd.edu wrote:

I’m a bit confused by the scope of local variables.

$ irb --simple-pompt

foo = “bar”
=> “bar”
def function
puts foo
end
=> nil
function
NameError: undefined local variable or method foo' for #<Object:0xf9000> from (irb):3:in function’
from (irb):5

Since ‘foo’ was defined before ‘function’ and both ‘function’ and ‘foo’
are in the same scope (I think) shouldn’t ‘function’ see ‘foo’?

That’s kind of how Perl’s scoping works, but not Ruby. The scope inside
your def function is different from the scope outside. So inside of
method ‘function’ there is no ‘knowledge’ of the foo variable that was
defined outside.

Phil

“Or perhaps the truth is less interesting than the facts?”
Amy Weiss (accusing theregister.co.uk of engaging in ‘tabloid journalism’)
Senior VP, Communications
Recording Industry Association of America

In article 3E2C5674.8020002@path.berkeley.edu,

···

Joel VanderWerf vjoel@PATH.Berkeley.EDU wrote:

Daniel Carrera wrote:

Since ‘foo’ was defined before ‘function’ and both ‘function’ and ‘foo’
are in the same scope (I think) shouldn’t ‘function’ see ‘foo’?

You can do this in 1.7:

module M
foo = “bar”
define_method :function do
puts foo
end
end
include M

function # prints: bar

This falls into the catagory of
one-of-those-1.8-features-I-didn’t-know-about.

So define_method can define a method that ‘knows’ about all of the
variables in the scope in which it is defined? Useful, but one needs to
be careful.

Phil


“Or perhaps the truth is less interesting than the facts?”
Amy Weiss (accusing theregister.co.uk of engaging in ‘tabloid journalism’)
Senior VP, Communications
Recording Industry Association of America

Hi,

···

At Tue, 21 Jan 2003 05:03:48 +0900, Joel VanderWerf wrote:

Since ‘foo’ was defined before ‘function’ and both ‘function’ and
‘foo’ are in the same scope (I think) shouldn’t ‘function’ see ‘foo’?

You can do this in 1.7:

This works in 1.6 too.


Nobu Nakada

this one works as expected:

irb(main):001:0> @@foo = “bar”
“bar”
irb(main):002:0> def function
irb(main):003:1> puts @@foo
irb(main):004:1> end
nil
irb(main):005:0> function
bar
nil
irb(main):006:0>

Note the “@@” which makes “foo” a module variable in the current module,
which thus can be seen by method “function”.

Regards

robert

“Phil Tomson” ptkwt@shell1.aracnet.com schrieb im Newsbeitrag
news:b0hori02poj@enews2.newsguy.com

In article 20030120193158.GA1029@math.umd.edu,

I’m a bit confused by the scope of local variables.

$ irb --simple-pompt

foo = “bar”
=> “bar”
def function
puts foo
end
=> nil
function
NameError: undefined local variable or method foo' for #<Object:0xf9000> from (irb):3:in function’
from (irb):5

Since ‘foo’ was defined before ‘function’ and both ‘function’ and ‘foo’
are in the same scope (I think) shouldn’t ‘function’ see ‘foo’?

That’s kind of how Perl’s scoping works, but not Ruby. The scope inside
your def function is different from the scope outside. So inside of
method ‘function’ there is no ‘knowledge’ of the foo variable that was
defined outside.

Phil

“Or perhaps the truth is less interesting than the facts?”
Amy Weiss (accusing theregister.co.uk of engaging in ‘tabloid
journalism’)

···

Daniel Carrera dcarrera@math.umd.edu wrote:
Senior VP, Communications
Recording Industry Association of America

You can do this in 1.7:

module M
foo = “bar”
define_method :function do
puts foo
end
end
include M

function # prints: bar

This falls into the catagory of
one-of-those-1.8-features-I-didn’t-know-about.

So define_method can define a method that ‘knows’ about all of the
variables in the scope in which it is defined? Useful, but one needs to
be careful.

Correct me if I’m wrong, but isn’t this simply
because the do/end block itself is able to “see”
the variable foo?

The body of an ordinary method, i.e., def/end,
looks similar to a do/end block but isn’t one.

This starts my mind speculating about the two
converging into one thing… but that would
likely raise more issues than it resolves. And
I certainly am not in the mood to think it
through. :slight_smile:

Hal

···

----- Original Message -----
From: “Phil Tomson” ptkwt@shell1.aracnet.com
Newsgroups: comp.lang.ruby
To: “ruby-talk ML” ruby-talk@ruby-lang.org
Sent: Monday, January 20, 2003 3:54 PM
Subject: Re: Local variable scope

Hal E. Fulton wrote:

module M
foo = “bar”
define_method :function do
puts foo
end
end
include M

function # prints: bar

[snip]

Correct me if I’m wrong, but isn’t this simply
because the do/end block itself is able to “see”
the variable foo?

The body of an ordinary method, i.e., def/end,
looks similar to a do/end block but isn’t one.

The following question is probably completely different to this thread,
but I’m going to ask it anyway (with the caveat for readers that I’ve
been playing with Ruby for, err, a week now).

I tried to do this yesterday:

def foo(foobar)
bar = 0;
if foobar != nil
bar = foobar * 4
else
bar = “foobar!”
end
bar
end

foo(3) → 0

from looking at it it seems that my problem is that the bar inside the
if/else block is not the same bar that is declared at the start of the
method.

how should I be doing the above? I ended up doing this:

def foo(foobar)
bar =
if foobar != nil
bar = foobar * 4
else
bar = “foobar!”
end
bar
end

which worked fine, but I was wondering if there was a way to do what I
was trying initially.

cheers and thanks
dim

(ps - code written from memory, and obviously a silly example, not the
real thing)

This works fine in my system. Check your code. Try this example on your
system.

···

On Tue, Jan 21, 2003 at 08:35:02AM +0900, Dmitri Colebatch wrote:

def foo(foobar)
bar = 0;
if foobar != nil
bar = foobar * 4
else
bar = “foobar!”
end
bar
end


Daniel Carrera
Graduate Teaching Assistant. Math Dept.
University of Maryland. (301) 405-5137

This should work fine. Offhand I’d say the problem
you’re having must be of a different nature.

There are shorter/prettier ways, depending on
your individual taste:

E.g.:

def foo(foobar)
if foobar.nil?
foobar*4
else
“foobar!”
end
end

Or even:

def foo(foobar)
foobar ? foobar*4 : “foobar!”
end

Cheers,
Hal

···

----- Original Message -----
From: “Dmitri Colebatch” dim@colebatch.com
To: “ruby-talk ML” ruby-talk@ruby-lang.org
Sent: Monday, January 20, 2003 5:35 PM
Subject: Re: Local variable scope

I tried to do this yesterday:

def foo(foobar)
bar = 0;
if foobar != nil
bar = foobar * 4
else
bar = “foobar!”
end
bar
end

Yes, the value of the last statement in an if/elsif/else/end block is
the value of the if :slight_smile: So you can just do this:

def foo(foobar)
bar =
if foobar != nil
foobar * 4
else
bar = “foobar!”
end
end
end

Or even shorter:

def foo(foobar)
if foobar != nil
foobar * 4
else
“foobar!”
end
end

Or you can go all C-style and do:

def foo(foobar) foobar.nil? ? “foobar” : foobar * 4 end

···

Dmitri Colebatch (dim@colebatch.com) wrote:

how should I be doing the above? I ended up doing this:

def foo(foobar)
bar =
if foobar != nil
bar = foobar * 4
else
bar = “foobar!”
end
bar
end

which worked fine, but I was wondering if there was a way to do what I
was trying initially.


Eric Hodel - drbrain@segment7.net - http://segment7.net
All messages signed with fingerprint:
FEC2 57F1 D465 EB15 5D6E 7C11 332A 551C 796C 9F04

Daniel Carrera wrote:

def foo(foobar)
bar = 0;
if foobar != nil
bar = foobar * 4
else
bar = “foobar!”
end
bar
end

This works fine in my system. Check your code. Try this example on your
system.

:smiley: always the way… ok, by works fine - I’m assuming the intent is
obvious (in that I expect it to return the arg multiplied by 4, or the
string “foobar!” if there is no arg passed in.

I’ve changed my old code - and didn’t checkin a broken version so dont
have what I was doing… but from what you’re saying this ought to work
as I expect it to and it was no doubt just me doing something stupid.

cheers
dim

···

On Tue, Jan 21, 2003 at 08:35:02AM +0900, Dmitri Colebatch wrote:

s/if/unless

···

On Tuesday, January 21, 2003, 10:51:01 AM, Hal wrote:

def foo(foobar)
if foobar.nil?
foobar*4
else
“foobar!”
end
end

Hal E. Fulton wrote:

From: “Dmitri Colebatch” dim@colebatch.com

I tried to do this yesterday:

def foo(foobar)
bar = 0;
if foobar != nil
bar = foobar * 4
else
bar = “foobar!”
end
bar
end

This should work fine. Offhand I’d say the problem
you’re having must be of a different nature.

There are shorter/prettier ways, depending on
your individual taste:

E.g.:

def foo(foobar)
if foobar.nil?
foobar*4
else
“foobar!”
end
end

Thanks - hadn’t spotted the .nil? method. I assume thats on Object.

Or even:

def foo(foobar)
foobar ? foobar*4 : “foobar!”
end

yeah, the actual code had a fair bit of logic in it, so I wanted the
block separation, but thanks all the same.

cheers
dim

···

----- Original Message -----

Hi –

···

On Tue, 21 Jan 2003, Eric Hodel wrote:

Dmitri Colebatch (dim@colebatch.com) wrote:

how should I be doing the above? I ended up doing this:

def foo(foobar)
bar =
if foobar != nil
bar = foobar * 4
else
bar = “foobar!”
end
bar
end

which worked fine, but I was wondering if there was a way to do what I
was trying initially.

Yes, the value of the last statement in an if/elsif/else/end block is
the value of the if :slight_smile: So you can just do this:

def foo(foobar)
bar =
if foobar != nil
foobar * 4
else
bar = “foobar!”

(You forgot to erase that last “bar =” :slight_smile:

I thought along with the if/else and ?: versions I’d throw in:

def foo(foobar)
foobar.nil? && “foobar!” || foobar * 4
end

David


David Alan Black
home: dblack@candle.superlink.net
work: blackdav@shu.edu
Web: http://pirate.shu.edu/~blackdav

:slight_smile: Yes… actually I guess you’d have to default it to
nil if you actually wanted it to accept NO ARGUMENT
passed in: def foo(foobar=nil)

Hal

···

----- Original Message -----
From: “Dmitri Colebatch” dim@colebatch.com
To: “ruby-talk ML” ruby-talk@ruby-lang.org
Sent: Monday, January 20, 2003 5:47 PM
Subject: Re: Local variable scope

:smiley: always the way… ok, by works fine - I’m assuming the intent is
obvious (in that I expect it to return the arg multiplied by 4, or the
string “foobar!” if there is no arg passed in.

Right, thanks.

Hal

···

----- Original Message -----
From: “Gavin Sinclair” gsinclair@soyabean.com.au
To: “ruby-talk ML” ruby-talk@ruby-lang.org
Sent: Monday, January 20, 2003 5:55 PM
Subject: Re: Local variable scope

s/if/unless

Just to emphasise the point. If you call your code with no
argument, the parser or whever you call it will spit the dummy. Just
as zero is a number, nil qualifies as an argument.

Gavin

···

On Tuesday, January 21, 2003, 10:52:40 AM, Hal wrote:

----- Original Message -----
From: “Dmitri Colebatch” dim@colebatch.com
To: “ruby-talk ML” ruby-talk@ruby-lang.org
Sent: Monday, January 20, 2003 5:47 PM
Subject: Re: Local variable scope

:smiley: always the way… ok, by works fine - I’m assuming the intent is
obvious (in that I expect it to return the arg multiplied by 4, or the
string “foobar!” if there is no arg passed in.

:slight_smile: Yes… actually I guess you’d have to default it to
nil if you actually wanted it to accept NO ARGUMENT
passed in: def foo(foobar=nil)

Gavin Sinclair wrote:

:slight_smile: Yes… actually I guess you’d have to default it to
nil if you actually wanted it to accept NO ARGUMENT
passed in: def foo(foobar=nil)

Just to emphasise the point. If you call your code with no
argument, the parser or whever you call it will spit the dummy. Just
as zero is a number, nil qualifies as an argument.

I’d effectively get a ‘array index out of bounds’ error or something
yeah? in that the array of arguments is zero length and because I
require one argument I’m doing something like:

foobar = [0]

which I assume will fail every time…

cheers
dim