[lnkForumImage]
TotalShareware - Download Free Software

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


 

Forums >

comp.lang.ruby

Struggling with Blocks

Greg Chagnon

9/10/2006 4:17:00 PM

I'm a new to Ruby, and struggling to understand the different kinds of blocks/procs/methods/lambadas
etc.

I found a good intro at
http://eli.thegreenplace.net/2006/04/18/understanding-ruby-blocks-procs-an..., but one thing
which it doesn't cover is begin/end. Why is a new keyword used, instead of adding rescue/else/ensure
to do/end blocks?

--
Posted via a free Usenet account from http://www.te...
Warning: Do not use Ultimate-Anonymity
They are worthless spammers that are running a scam.

38 Answers

Paul Lutus

9/10/2006 5:02:00 PM

0

Newbie wrote:

> I'm a new to Ruby, and struggling to understand the different kinds of
> blocks/procs/methods/lambadas etc.
>
> I found a good intro at
>
http://eli.thegreenplace.net/2006/04/18/understanding-ruby-blocks-procs-an...,
> but one thing which it doesn't cover is begin/end. Why is a new keyword
> used, instead of adding rescue/else/ensure to do/end blocks?

To put it in simplest terms, the keyword "do" must be preceded by a data
source, while the keyword "begin" doesn't. So "begin" meets a syntactical
requirement that "do" doesn't.

Maybe this will help:

# valid:

1.upto(10) do |x|
puts x
end

# not valid:

do |x|
puts x
end

# valid:

begin
# normal process
rescue
# deal with errors
else
# no-errors section
ensure
# always-run section
end

# also valid:

x = 0

begin
puts x
x += 1
end while x <= 10

# also valid:

x = 0

begin
puts x
x += 1
end until x > 10

# even this works:

x = 0

begin
puts x
x += 1
x /= 0 if x == 8 # generate an error
rescue
puts "Error!"
end until x > 10

The last form emits this:

0
1
2
3
4
5
6
7
Error!
8
9
10


HTH

--
Paul Lutus
http://www.ara...

Greg Chagnon

9/10/2006 6:05:00 PM

0

Perhaps I wasn't clear enough in my question (or misunderstood your answer). I'm trying to
understand a design decision - why isn't do/end used for begin/end scenarios?

Paul Lutus wrote:
> To put it in simplest terms, the keyword "do" must be preceded by a data
> source, while the keyword "begin" doesn't. So "begin" meets a syntactical
> requirement that "do" doesn't.
>
> Maybe this will help:
>
> # valid:
>
> 1.upto(10) do |x|
> puts x
> end
>
> # not valid:
>
> do |x|
> puts x
> end
>
> # valid:
>
> begin
> # normal process
> rescue
> # deal with errors
> else
> # no-errors section
> ensure
> # always-run section
> end
>
> # also valid:
>
> x = 0
>
> begin
> puts x
> x += 1
> end while x <= 10
>
> # also valid:
>
> x = 0
>
> begin
> puts x
> x += 1
> end until x > 10
>
> # even this works:
>
> x = 0
>
> begin
> puts x
> x += 1
> x /= 0 if x == 8 # generate an error
> rescue
> puts "Error!"
> end until x > 10
>
> The last form emits this:
>
> 0
> 1
> 2
> 3
> 4
> 5
> 6
> 7
> Error!
> 8
> 9
> 10
>
>
> HTH
>

--
Posted via a free Usenet account from http://www.te...
Warning: Do not use Ultimate-Anonymity
They are worthless spammers that are running a scam.

Paul Lutus

9/10/2006 6:49:00 PM

0

Newbie wrote:

> Perhaps I wasn't clear enough in my question (or misunderstood your
> answer). I'm trying to understand a design decision - why isn't do/end
> used for begin/end scenarios?

Because do ... end functions differently than begin ... end, and begin ...
end is necessary for goals where do ... end just won't do. And vice versa.
They have distinct purposes.

A begin ... end block can be nested within a do ... end block (and vice
versa), to mix iteration with the rescue feature.

--
Paul Lutus
http://www.ara...

Greg Chagnon

9/10/2006 6:55:00 PM

0

So, from a language design perspective, what would be wrong with this?

do
stuff
do
risky stuff
rescue
SOS
end
more stuff
end while bored

or

do
risky stuff
rescue
SOS
end while bored

Paul Lutus wrote:
> Because do ... end functions differently than begin ... end, and begin ...
> end is necessary for goals where do ... end just won't do. And vice versa.
> They have distinct purposes.
>
> A begin ... end block can be nested within a do ... end block (and vice
> versa), to mix iteration with the rescue feature.

--
Posted via a free Usenet account from http://www.te...
Warning: Do not use Ultimate-Anonymity
They are worthless spammers that are running a scam.

Paul Lutus

9/10/2006 10:05:00 PM

0

Newbie wrote:

> So, from a language design perspective, what would be wrong with this?
>
> do
> stuff
> do
> risky stuff
> rescue
> SOS
> end
> more stuff
> end while bored

"do" doesn't work this way -- it's an iterator (loosely speaking). "begin"
is not an iterator. They are different. There are good reasons to make this
distinction.

--
Paul Lutus
http://www.ara...

Ken Bloom

9/10/2006 10:08:00 PM

0

On Sun, 10 Sep 2006 15:05:10 -0700, Paul Lutus wrote:

> Newbie wrote:
>
>> So, from a language design perspective, what would be wrong with this?
>>
>> do
>> stuff
>> do
>> risky stuff
>> rescue
>> SOS
>> end
>> more stuff
>> end while bored
>
> "do" doesn't work this way -- it's an iterator (loosely speaking). "begin"
> is not an iterator. They are different. There are good reasons to make this
> distinction.
>

What *are* those reasons? That's the whole point of his question.

--
Ken Bloom. PhD candidate. Linguistic Cognition Laboratory.
Department of Computer Science. Illinois Institute of Technology.
http://www.iit.edu...

Paul Lutus

9/10/2006 10:40:00 PM

0

Ken Bloom wrote:

> On Sun, 10 Sep 2006 15:05:10 -0700, Paul Lutus wrote:
>
>> Newbie wrote:
>>
>>> So, from a language design perspective, what would be wrong with this?
>>>
>>> do
>>> stuff
>>> do
>>> risky stuff
>>> rescue
>>> SOS
>>> end
>>> more stuff
>>> end while bored
>>
>> "do" doesn't work this way -- it's an iterator (loosely speaking).
>> "begin" is not an iterator. They are different. There are good reasons to
>> make this distinction.
>>
>
> What *are* those reasons? That's the whole point of his question.

"do" reads from a list of items and provides them to its controlling block:

(implicit "do")

array.each { |item|
# do something here
}

(explicit "do")

array.each do |item|
# do something here
end

These two forms are interchangeable. One can argue that "do" is an implicit
"{ ... }" block, or the reverse. But the point is "do" receives items and
operates on them one at a time, then exits when its stream is empty.

"begin" doesn't get fed with items, it has a different purpose. It
demarcates a controlled block, to which a "rescue" clause might apply, or
to which a "while" test might apply, or others. And a "begin" block won't
persist on its own. Without some internal block that does something
repetitive (or a "while" test at the end), the "begin" block will exit in
one pass.

There is a need for both "do" and "begin" blocks. There is a need to
distinguish syntactically between a block that must be fed with items, and
one that must not be fed with items. To combine "do" and "begin" would lead
to syntactical ambiguity ... and surely then someone would ask why the two
purposes of "do" were not more clearly distinguished in the syntax.

If "do" and "begin" were to be merged, it would be a little like the
ambiguous use of "<<" in C++. In one context, it shifts bits:

int x = 1,y;

y = x << 4; // y = 16

In another context, "<<" inserts items into a stream:

iostream x;
bool y;

y = x << 4; // y = true if the operation was successful

See the problem? Without my clear declarations directly above each case, you
would have a hard time distinguishing cases that use the same syntax. This
would make program listings hard to interpret and debug (a fact in C++).

The multiple uses of "<<" in C++ is a well-known example, but the point I am
making is that it's important to avoid ambiguous syntax in language design.
"do ... end" always has a stream, and when the stream is exhausted, the
block exits. "begin ... end" never has a stream. It's easy to remember and
easy to read.

The end result of responding to every request for creative syntax variations
is called ... umm ... "Perl". :)

--
Paul Lutus
http://www.ara...

Logan Capaldo

9/10/2006 11:49:00 PM

0

On Mon, Sep 11, 2006 at 07:45:28AM +0900, Paul Lutus wrote:
> There is a need for both "do" and "begin" blocks. There is a need to
> distinguish syntactically between a block that must be fed with items, and
> one that must not be fed with items. To combine "do" and "begin" would lead
> to syntactical ambiguity ... and surely then someone would ask why the two
> purposes of "do" were not more clearly distinguished in the syntax.
>
> If "do" and "begin" were to be merged, it would be a little like the
> ambiguous use of "<<" in C++. In one context, it shifts bits:
>
> int x = 1,y;
>
> y = x << 4; // y = 16
>
> In another context, "<<" inserts items into a stream:
>
> iostream x;
> bool y;
>
> y = x << 4; // y = true if the operation was successful
>
> See the problem? Without my clear declarations directly above each case, you
> would have a hard time distinguishing cases that use the same syntax. This
> would make program listings hard to interpret and debug (a fact in C++).
>
> The multiple uses of "<<" in C++ is a well-known example, but the point I am
> making is that it's important to avoid ambiguous syntax in language design.
> "do ... end" always has a stream, and when the stream is exhausted, the
> block exits. "begin ... end" never has a stream. It's easy to remember and
> easy to read.
>
> The end result of responding to every request for creative syntax variations
> is called ... umm ... "Perl". :)
>
Excellent argument, poor choice of example code *cough*.

a = 1 #=> 1
a << 1 #=> 2
$stdout << 4 # outputs '4'


Joseph

9/11/2006 12:02:00 AM

0

Excellent explanation Paul... I guess many newbies, and not so new are
grateful.

Regards,

Jose L. Hurtado
Web Developer
Toronto, Canada

Paul Lutus wrote:
> Ken Bloom wrote:
>
> > On Sun, 10 Sep 2006 15:05:10 -0700, Paul Lutus wrote:
> >
> >> Newbie wrote:
> >>
> >>> So, from a language design perspective, what would be wrong with this?
> >>>
> >>> do
> >>> stuff
> >>> do
> >>> risky stuff
> >>> rescue
> >>> SOS
> >>> end
> >>> more stuff
> >>> end while bored
> >>
> >> "do" doesn't work this way -- it's an iterator (loosely speaking).
> >> "begin" is not an iterator. They are different. There are good reasons to
> >> make this distinction.
> >>
> >
> > What *are* those reasons? That's the whole point of his question.
>
> "do" reads from a list of items and provides them to its controlling block:
>
> (implicit "do")
>
> array.each { |item|
> # do something here
> }
>
> (explicit "do")
>
> array.each do |item|
> # do something here
> end
>
> These two forms are interchangeable. One can argue that "do" is an implicit
> "{ ... }" block, or the reverse. But the point is "do" receives items and
> operates on them one at a time, then exits when its stream is empty.
>
> "begin" doesn't get fed with items, it has a different purpose. It
> demarcates a controlled block, to which a "rescue" clause might apply, or
> to which a "while" test might apply, or others. And a "begin" block won't
> persist on its own. Without some internal block that does something
> repetitive (or a "while" test at the end), the "begin" block will exit in
> one pass.
>
> There is a need for both "do" and "begin" blocks. There is a need to
> distinguish syntactically between a block that must be fed with items, and
> one that must not be fed with items. To combine "do" and "begin" would lead
> to syntactical ambiguity ... and surely then someone would ask why the two
> purposes of "do" were not more clearly distinguished in the syntax.
>
> If "do" and "begin" were to be merged, it would be a little like the
> ambiguous use of "<<" in C++. In one context, it shifts bits:
>
> int x = 1,y;
>
> y = x << 4; // y = 16
>
> In another context, "<<" inserts items into a stream:
>
> iostream x;
> bool y;
>
> y = x << 4; // y = true if the operation was successful
>
> See the problem? Without my clear declarations directly above each case, you
> would have a hard time distinguishing cases that use the same syntax. This
> would make program listings hard to interpret and debug (a fact in C++).
>
> The multiple uses of "<<" in C++ is a well-known example, but the point I am
> making is that it's important to avoid ambiguous syntax in language design.
> "do ... end" always has a stream, and when the stream is exhausted, the
> block exits. "begin ... end" never has a stream. It's easy to remember and
> easy to read.
>
> The end result of responding to every request for creative syntax variations
> is called ... umm ... "Perl". :)
>
> --
> Paul Lutus
> http://www.ara...

Hal E. Fulton

9/11/2006 12:16:00 AM

0

Paul Lutus wrote:
>
> "do" reads from a list of items and provides them to its controlling block:
>
> These two forms are interchangeable. One can argue that "do" is an implicit
> "{ ... }" block, or the reverse. But the point is "do" receives items and
> operates on them one at a time, then exits when its stream is empty.

Not strictly true. Reemember that the iteration comes from the fact
that the each method is invoking the block multiple times.

Here's a do/end that will only execute once (and by the way
has no parameters):

Dir.chdir(some_dir) do process_something end

And by the way, the rescue that can appear between def and end
is rather an example of what some people want, IIUC. My impression
is that do/end don't have a rescue basically to avoid unneeded
complexity and because putting rescue inside {} for orthognality
looks questionable.


Hal