[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

I thought this was the one that worked?

Eric Armstrong

7/31/2006 6:49:00 PM

#!/usr/bin/env ruby

repeat = 1

def run
number_of_times = repeat
number_of_times.downto(0) do
puts number_of_times
sleep 1
end
end

run
----------------------------

Fails: undefined variable, "repeat"
in first line of run method

I would have sworn that this was the
one that worked. I know that for a class
definition, the value of "repeat" isn't
known in an instance. That makes sense
to me (now).

But here, I'm in a script. I am continually
surprised by this behavior. In my mental
model, the run method is a "subsidiary"
context of the larger context, and as such
it should just "naturally" be aware of values
defined in the wider context.

Obviously, my mental model is way, way off,
which is why I keep getting surprised. Can
anyone enlighten me?

thanks
eric



134 Answers

Logan Capaldo

7/31/2006 7:23:00 PM

0


On Jul 31, 2006, at 2:49 PM, Eric Armstrong wrote:

> #!/usr/bin/env ruby
>
> repeat = 1
>
> def run
> number_of_times = repeat
> number_of_times.downto(0) do
> puts number_of_times
> sleep 1
> end
> end
>
> run
> ----------------------------
>
> Fails: undefined variable, "repeat"
> in first line of run method
>
> I would have sworn that this was the
> one that worked. I know that for a class
> definition, the value of "repeat" isn't
> known in an instance. That makes sense
> to me (now).
>
> But here, I'm in a script. I am continually
> surprised by this behavior. In my mental
> model, the run method is a "subsidiary"
> context of the larger context, and as such
> it should just "naturally" be aware of values
> defined in the wider context.
>
> Obviously, my mental model is way, way off,
> which is why I keep getting surprised. Can
> anyone enlighten me?
>
> thanks
> eric
>
>
>

repeat is a local variable. class, def, and module introduce a new
scope without closing over their enclosing scope. Blocks introduce a
new scope that does enclose it's enclosing scope.

repeat = 1 # local variable repeat

def run # I just introduced a new scope. I can't see local variables
outside my body


define_method("run") { # I just introduced a new scope, but I'm also
a closure, I can see repeat.

Note that this issue has nothing to do with instances vs. classes, etc.



Chad Perrin

7/31/2006 7:31:00 PM

0

On Tue, Aug 01, 2006 at 04:23:27AM +0900, Logan Capaldo wrote:
>
> repeat is a local variable. class, def, and module introduce a new
> scope without closing over their enclosing scope. Blocks introduce a
> new scope that does enclose it's enclosing scope.

As I understand it, this means that class, def, and module use dynamic
local scope, and blocks use static/lexical scope. Is that accurate?

--
CCD CopyWrite Chad Perrin [ http://ccd.ap... ]
"Real ugliness is not harsh-looking syntax, but having to
build programs out of the wrong concepts." - Paul Graham

Logan Capaldo

7/31/2006 7:58:00 PM

0


On Jul 31, 2006, at 3:30 PM, Chad Perrin wrote:

> On Tue, Aug 01, 2006 at 04:23:27AM +0900, Logan Capaldo wrote:
>>
>> repeat is a local variable. class, def, and module introduce a new
>> scope without closing over their enclosing scope. Blocks introduce a
>> new scope that does enclose it's enclosing scope.
>
> As I understand it, this means that class, def, and module use dynamic
> local scope, and blocks use static/lexical scope. Is that accurate?
>
All these examples are lexical scoping. Ruby doesn't really have
dynamic scoping although you can sort of abuse instance variables to
achieve similar effects.

The difference is that blocks are closures, where def, class, and
module aren't.



> --
> CCD CopyWrite Chad Perrin [ http://ccd.ap... ]
> "Real ugliness is not harsh-looking syntax, but having to
> build programs out of the wrong concepts." - Paul Graham
>


Chad Perrin

7/31/2006 9:14:00 PM

0

On Tue, Aug 01, 2006 at 04:57:48AM +0900, Logan Capaldo wrote:
>
> All these examples are lexical scoping. Ruby doesn't really have
> dynamic scoping although you can sort of abuse instance variables to
> achieve similar effects.
>
> The difference is that blocks are closures, where def, class, and
> module aren't.

Wait . . . you mean that *all blocks* are automagically lexical
closures, as though declared lexical variables within them have gone out
of scope? I imagine I'm probably misunderstanding you, but if not,
that's a pretty nifty bit of trickery.

--
CCD CopyWrite Chad Perrin [ http://ccd.ap... ]
Ben Franklin: "As we enjoy great Advantages from the Inventions of
others we should be glad of an Opportunity to serve others by any
Invention of ours, and this we should do freely and generously."

Logan Capaldo

7/31/2006 10:06:00 PM

0


On Jul 31, 2006, at 5:13 PM, Chad Perrin wrote:

> On Tue, Aug 01, 2006 at 04:57:48AM +0900, Logan Capaldo wrote:
>>
>> All these examples are lexical scoping. Ruby doesn't really have
>> dynamic scoping although you can sort of abuse instance variables to
>> achieve similar effects.
>>
>> The difference is that blocks are closures, where def, class, and
>> module aren't.
>
> Wait . . . you mean that *all blocks* are automagically lexical
> closures, as though declared lexical variables within them have
> gone out
> of scope? I imagine I'm probably misunderstanding you, but if not,
> that's a pretty nifty bit of trickery.
>
I'm not sure I understand your question. All blocks (by blocks I mean
do / end and { } ) are (lexically scoped) closures.




> --
> CCD CopyWrite Chad Perrin [ http://ccd.ap... ]
> Ben Franklin: "As we enjoy great Advantages from the Inventions of
> others we should be glad of an Opportunity to serve others by any
> Invention of ours, and this we should do freely and generously."
>


Chad Perrin

7/31/2006 10:48:00 PM

0

On Tue, Aug 01, 2006 at 07:05:31AM +0900, Logan Capaldo wrote:
>
> On Jul 31, 2006, at 5:13 PM, Chad Perrin wrote:
>
> >On Tue, Aug 01, 2006 at 04:57:48AM +0900, Logan Capaldo wrote:
> >>
> >>All these examples are lexical scoping. Ruby doesn't really have
> >>dynamic scoping although you can sort of abuse instance variables to
> >>achieve similar effects.
> >>
> >>The difference is that blocks are closures, where def, class, and
> >>module aren't.
> >
> >Wait . . . you mean that *all blocks* are automagically lexical
> >closures, as though declared lexical variables within them have
> >gone out
> >of scope? I imagine I'm probably misunderstanding you, but if not,
> >that's a pretty nifty bit of trickery.
> >
> I'm not sure I understand your question. All blocks (by blocks I mean
> do / end and { } ) are (lexically scoped) closures.

I'll use a Perl example:

sub foo {
my $bar = 1;
return sub { print ++$bar };
}

my $baz = foo();

Voila. $baz contains a lexical closure. This is the case because the
return value from foo() was lexically "closed" by virtue of $bar going
out of scope, but its value still being accessible via the coderef
returned from foo() and assigned to $baz.

--
CCD CopyWrite Chad Perrin [ http://ccd.ap... ]
"The measure on a man's real character is what he would do
if he knew he would never be found out." - Thomas McCauley

Jacob Fugal

7/31/2006 10:55:00 PM

0

On 7/31/06, Chad Perrin <perrin@apotheon.com> wrote:
> On Tue, Aug 01, 2006 at 07:05:31AM +0900, Logan Capaldo wrote:
> > I'm not sure I understand your question. All blocks (by blocks I mean
> > do / end and { } ) are (lexically scoped) closures.
>
> I'll use a Perl example:
>
> sub foo {
> my $bar = 1;
> return sub { print ++$bar };
> }
>
> my $baz = foo();
>
> Voila. $baz contains a lexical closure. This is the case because the
> return value from foo() was lexically "closed" by virtue of $bar going
> out of scope, but its value still being accessible via the coderef
> returned from foo() and assigned to $baz.

How is this different from:

def foo
bar = 1
return proc{ bar += 1; puts bar }
end

begin
puts bar
rescue Exception => e
puts e
end
# => undefined local variable or method `bar' for main:Object

baz = foo
baz.call # => 2
baz.call # => 3
baz.call # => 4
...

Jacob Fugal

Chad Perrin

7/31/2006 11:07:00 PM

0

On Tue, Aug 01, 2006 at 07:54:33AM +0900, Jacob Fugal wrote:
> On 7/31/06, Chad Perrin <perrin@apotheon.com> wrote:
> >On Tue, Aug 01, 2006 at 07:05:31AM +0900, Logan Capaldo wrote:
> >> I'm not sure I understand your question. All blocks (by blocks I mean
> >> do / end and { } ) are (lexically scoped) closures.
> >
> >I'll use a Perl example:
> >
> >sub foo {
> > my $bar = 1;
> > return sub { print ++$bar };
> >}
> >
> >my $baz = foo();
> >
> >Voila. $baz contains a lexical closure. This is the case because the
> >return value from foo() was lexically "closed" by virtue of $bar going
> >out of scope, but its value still being accessible via the coderef
> >returned from foo() and assigned to $baz.
>
> How is this different from:
>
> def foo
> bar = 1
> return proc{ bar += 1; puts bar }
> end
>
> begin
> puts bar
> rescue Exception => e
> puts e
> end
> # => undefined local variable or method `bar' for main:Object
>
> baz = foo
> baz.call # => 2
> baz.call # => 3
> baz.call # => 4

Who said it's different? I'm just asking about the foregoing statement
that all blocks are closures (which strikes me as improbable). That's
like saying that this will generate a closure (which it won't):

sub foo {
return sub { my $bar = 1; print ++$bar };
}

--
CCD CopyWrite Chad Perrin [ http://ccd.ap... ]
print substr("Just another Perl hacker", 0, -2);

Logan Capaldo

8/1/2006 12:50:00 AM

0


On Jul 31, 2006, at 6:48 PM, Chad Perrin wrote:

> On Tue, Aug 01, 2006 at 07:05:31AM +0900, Logan Capaldo wrote:
>>
>> On Jul 31, 2006, at 5:13 PM, Chad Perrin wrote:
>>
>>> On Tue, Aug 01, 2006 at 04:57:48AM +0900, Logan Capaldo wrote:
>>>>
>>>> All these examples are lexical scoping. Ruby doesn't really have
>>>> dynamic scoping although you can sort of abuse instance
>>>> variables to
>>>> achieve similar effects.
>>>>
>>>> The difference is that blocks are closures, where def, class, and
>>>> module aren't.
>>>
>>> Wait . . . you mean that *all blocks* are automagically lexical
>>> closures, as though declared lexical variables within them have
>>> gone out
>>> of scope? I imagine I'm probably misunderstanding you, but if not,
>>> that's a pretty nifty bit of trickery.
>>>
>> I'm not sure I understand your question. All blocks (by blocks I mean
>> do / end and { } ) are (lexically scoped) closures.
>
> I'll use a Perl example:
>
> sub foo {
> my $bar = 1;
> return sub { print ++$bar };
> }
>
> my $baz = foo();
>
> Voila. $baz contains a lexical closure. This is the case because the
> return value from foo() was lexically "closed" by virtue of $bar going
> out of scope, but its value still being accessible via the coderef
> returned from foo() and assigned to $baz.
>

Yes. It is just like perl.

% cat closure.rb
def foo
bar = 1
lambda { puts (bar += 1) }
end

baz = foo()

baz.call
baz.call

% ruby closure.rb
-:13: warning: don't put space before argument parentheses
2
3



> --
> CCD CopyWrite Chad Perrin [ http://ccd.ap... ]
> "The measure on a man's real character is what he would do
> if he knew he would never be found out." - Thomas McCauley
>


Logan Capaldo

8/1/2006 12:57:00 AM

0


On Jul 31, 2006, at 7:07 PM, Chad Perrin wrote:

> On Tue, Aug 01, 2006 at 07:54:33AM +0900, Jacob Fugal wrote:
>> On 7/31/06, Chad Perrin <perrin@apotheon.com> wrote:
>>> On Tue, Aug 01, 2006 at 07:05:31AM +0900, Logan Capaldo wrote:
>>>> I'm not sure I understand your question. All blocks (by blocks I
>>>> mean
>>>> do / end and { } ) are (lexically scoped) closures.
>>>
>>> I'll use a Perl example:
>>>
>>> sub foo {
>>> my $bar = 1;
>>> return sub { print ++$bar };
>>> }
>>>
>>> my $baz = foo();
>>>
>>> Voila. $baz contains a lexical closure. This is the case
>>> because the
>>> return value from foo() was lexically "closed" by virtue of $bar
>>> going
>>> out of scope, but its value still being accessible via the coderef
>>> returned from foo() and assigned to $baz.
>>
>> How is this different from:
>>
>> def foo
>> bar = 1
>> return proc{ bar += 1; puts bar }
>> end
>>
>> begin
>> puts bar
>> rescue Exception => e
>> puts e
>> end
>> # => undefined local variable or method `bar' for main:Object
>>
>> baz = foo
>> baz.call # => 2
>> baz.call # => 3
>> baz.call # => 4
>
> Who said it's different? I'm just asking about the foregoing
> statement
> that all blocks are closures (which strikes me as improbable). That's
> like saying that this will generate a closure (which it won't):
>
> sub foo {
> return sub { my $bar = 1; print ++$bar };
> }
>

In ruby it does. I'm having difficulty thinking of a simple example
to demonstrate it, but basically it grabs the whole environment
whether theres a reference to a variable or not. It does this to
allow things like:

def foo
x = 1
lambda { puts eval("X".downcase) }
end

You might say, so it just notices that you're using eval. But
consider this:

def bar
x = 1
lambda { puts send("lave".reverse, "y".sub(/y/, 'x')) }
end

Obviously contrived examples, but this is part of the reason blocks
"leak" memory.



> --
> CCD CopyWrite Chad Perrin [ http://ccd.ap... ]
> print substr("Just another Perl hacker", 0, -2);
>