Struggling with Blocks

Paul Lutus wrote:

···

gwtmp01@mac.com wrote:

But the point is "do" receives
items and
operates on them one at a time, then exits when its stream is empty.

This just doesn't sound right to me.

I was wrong. I should have thought a bit more deeply about what I was
saying. See my other post on this topic.

It's inspiring when someone can say the three magic words
"I was wrong" and move on.

That sounds sarcastic, but it's not meant to be. Can you
consider how much farther along the human race would be
if we all developed this skill?

Hal

Hal Fulton wrote:

> Paul Lutus wrote:
>> "do" reads from a list of items and provides them to its controlling
>> block:
> Not strictly true. Reemember that the iteration comes from the fact
> that the each method is invoking the block multiple times.
Yes, you are right (an I am quite wrong in the above quotation). The "do ...
end" block is simply a closure with an alternate syntax, and the calling
method provides the data and any repetition that may exist.

---------------------------------------------------

#! /usr/bin/ruby

def my_funct
   1.upto(8) do |x|
      yield x
   end
end

my_funct do |item|
   puts item
end

(or, equivalently)

my_funct { |item|
   puts item
}

So it appears that the syntactic role played by "do" is that it receives and
acts on the data fed to it by the calling method, once (barring any
repetitions internal to the do ... end block). IOW it is a closure block,
nothing more. Any looping is in the hands of the calling method.

While it is true in that in the most common case of do..end (or {..}),
i.e. when used as an argument to an iterator method, there are
argument involved, it's not necessarily so.

It's a syntactic 'feature' of Ruby that a do..end can only appear in a
method call, well actually there are two exceptions, see below. The
method being called has other options with what it can do with the
block than yielding a series of values to it.

irb(main):001:0> to_s_proc = lambda do |arg| arg.to_s; end
=> #<Proc:0xb7dd99f8@(irb):1>

irb(main):002:0> to_s_proc.call(1)
=> "1"

In this case lamba takes the block literal delimited by do..end and
turns it into a proc. The proc can later be called by anyone with a
reference to it. An example of such a use might be to implement a
'call-back' in a GUI framework, where the proc would be something to
be called, say when a button was pushed, although in this case a proc
with a side-effect is more likely to be used. Note that there's no
necessity for such a 'call-back' proc to take any arguments.

And it's possible to use a proc passed in on method call in a later iterator

irb(main):003:0>[1, 2, 1.3].map(&to_s_proc)
=> ["1", "2", "1.3"]

Now for those exceptions I noted above.

until boolean_expression do
     body
end

and

while boolean_expression do
     body
end

These both execute body either until or while boolean_expression
evaluates to true. In these two cases do..end are purely syntactic
entities, no block is created.

Another construct might LOOK like an exception:

for name [,name]... in expression do
    body
end

But it really isn't. Here the do..end does delimit a proc, and this
construct acts as if it were:

    expression.each do | name [,name]... |
            body
    end

except for one little quirk, in this case any local variables defined
in body will be accessible outside the loop.

So it appears the only difference between "do ... end" and "begin ... end"
is that "begin ... end" doesn't receive data from a caller.

Now we've just seen three cases where do doesn't receive data at all.

So, what's the real deal with BEGIN..END. What it really does is to
delimit a series of statements which are treated like an anonymous
method which is called in place. In other words when the begin is
entered the equivalent of a execution context is placed on the call
stack. It's this which enables the error handling. The rescue
clauses get associated with this call context.

When an exception is raised, the call stack gets scanned for a context
which contains a matching rescue clause.

So a more accurate statement of the difference between do..end, and
begin..end is that entering a begin..end stacks an execution context,
as does entering a method, whereas do..end does not.

And that's why you can put rescue clauses in a method definition, or
in a begin..end expression, but not directly in do..end.

···

On 9/10/06, Paul Lutus <nospam@nosite.zzz> wrote:
--
Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/

Hal Fulton wrote:

/ ...

It's inspiring when someone can say the three magic words
"I was wrong" and move on.

That sounds sarcastic, but it's not meant to be. Can you
consider how much farther along the human race would be
if we all developed this skill?

Off-topic. I have a personal stake in this business of acknowledging error.
Please read this if you have time:

http://www.arachnoid.com/psychology/narcissism.php

···

--
Paul Lutus
http://www.arachnoid.com

That's what I thought until recently, but there is a difference. Consider:

<code>
a = 1
begin
    a = 2
    b = 3
    p [a, b] # => [2, 3]
end
p a # => 2
p b # => 3
</code>

If the begin ... end behaved _exactly_ like an anonymous method, we would see:

<code>
a = 1
begin
    a = 2
    b = 3
    p [a, b] # => [2, 3]
end
p a # => 1
p b # => raises NameError
</code>

Frankly, I would be happier with the latter behavior.

Regards, Morton

···

On Sep 11, 2006, at 1:55 PM, Rick DeNatale wrote:

So, what's the real deal with BEGIN..END. What it really does is to
delimit a series of statements which are treated like an anonymous
method which is called in place.

+10

Gary Wright

···

On Sep 11, 2006, at 1:31 AM, Hal Fulton wrote:

Paul Lutus wrote:

gwtmp01@mac.com wrote:

But the point is "do" receives
items and
operates on them one at a time, then exits when its stream is empty.

This just doesn't sound right to me.

I was wrong. I should have thought a bit more deeply about what I was
saying. See my other post on this topic.

It's inspiring when someone can say the three magic words
"I was wrong" and move on.

That sounds sarcastic, but it's not meant to be. Can you
consider how much farther along the human race would be
if we all developed this skill?

I have to admit that I was struggling a bit when I made the analogy to
an anonymous method. The key is that begin pushes a new stack frame
onto the call stack.

You are right about the scoping of local variables.

···

On 9/11/06, Morton Goldberg <m_goldberg@ameritech.net> wrote:

On Sep 11, 2006, at 1:55 PM, Rick DeNatale wrote:

> So, what's the real deal with BEGIN..END. What it really does is to
> delimit a series of statements which are treated like an anonymous
> method which is called in place.

That's what I thought until recently, but there is a difference.
Consider:

<code>
a = 1
begin
    a = 2
    b = 3
    p [a, b] # => [2, 3]
end
p a # => 2
p b # => 3
</code>

If the begin ... end behaved _exactly_ like an anonymous method, we
would see:

<code>
a = 1
begin
    a = 2
    b = 3
    p [a, b] # => [2, 3]
end
p a # => 1
p b # => raises NameError
</code>

Frankly, I would be happier with the latter behavior.

--
Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/

The problem -- for me -- is that I can also make the analogy that 'begin ... end' is like 'lambda do ... end.call' with about the same degree of accuracy (or inaccuracy if you prefer). This second analogy would reflect the scoping rules better, but is a worse fit than your analogy when 'rescue', 'else', 'ensure', are added to the equation. If 'lambda do ... end' were to acquire the semantics of 'lambda do; begin ... end; end', then the analogy would be (almost?) exact and the OP less confused, but perhaps I'm begging the question more than clarifying anything. Also, such a change might introduce problems that haven't occurred to me. So I'm not proposing an RCR.

Nonetheless, I have sympathy for the OP. The different semantics of 'begin ... end' and 'do ... end' _are_ confusing.

Regards, Morton

···

On Sep 11, 2006, at 9:39 PM, Rick DeNatale wrote:

I have to admit that I was struggling a bit when I made the analogy to
an anonymous method. The key is that begin pushes a new stack frame
onto the call stack.

You are right about the scoping of local variables.

Having spent a bit more time perusing the 1.8 source code, my analogy
was a little off.

What really happens is that the rescue and ensure statements
effectively push a tag onto a stack which comprises local variables on
the C call stack, and then do a setjmp before executing the code being
protected, the tag contains the jmp_buf for setjmp, along with other
state needed for exception handling. Raising the exception does a
longjmp to the jmp_buf in the tag on the top of the stack, passing a
state which indicates that an exception is being raised.

The tag stack is also used for other purposes such as implementing
break, next, redo, and retry in loops.

Now I guess I could say that this "kind of" like an internal call, but
it's stretching things a bit further than I'd like

The break...end statement really just serves as a syntactic marker to
delimit where a series of statements being protected by
rescue/else/ensure starts, and where the last rescue/else/ensure ends.
If a begin..end sequence doesn't contain any rescue/ensure clauses, it
has no effect.

def..end also can mark those protected statements, although it also
serves the purpose of delimiting a method.

Now there might be a reason why the do..end, or {..} of a block can't
have the same feature, but I'm scratching my head to figure out why.
You CAN have a block which contains a single statement with a rescue
modifier:

    lambda do
         raise "help!" rescue "gotcha"
    end

is legal as is the semantically equivalent:

   lambda {raise "help!" rescue "gotcha"}

but

   lambda do
           raise "help!"
           rescue
                 "gotcha"
   end

is not.

Perhaps someone else (Matz?) can enlighten me/us on why

···

On 9/11/06, Rick DeNatale <rick.denatale@gmail.com> wrote:

I have to admit that I was struggling a bit when I made the analogy to
an anonymous method. The key is that begin pushes a new stack frame
onto the call stack.

You are right about the scoping of local variables.

--
Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/

There is certainly a syntactic similarity to begin/end and do/end but why are the semantics of those particular pairs confusing?
Why stop there? You also have to deal with: module/end, class/end, def/end, if/end, case/end.

At some point you just have to realize that different syntactic blocks have different semantics and then learn the semantics.

Gary Wright

···

On Sep 12, 2006, at 2:08 AM, Morton Goldberg wrote:

I have to admit that I was struggling a bit when I made the analogy to
an'm begging the question more than clarifying anything. Also, such a change might introduce problems that haven't occurred to me. So I'm not proposing an RCR.

Nonetheless, I have sympathy for the OP. The different semantics of 'begin ... end' and 'do ... end' _are_ confusing.

Even without further explication, the above is already enlightening. Thanks for taking the time and trouble to research this and write it up.

Regards, Morton

···

On Sep 12, 2006, at 12:39 PM, Rick DeNatale wrote:

On 9/11/06, Rick DeNatale <rick.denatale@gmail.com> wrote:
Having spent a bit more time perusing the 1.8 source code, my analogy
was a little off.

What really happens is that the rescue and ensure statements
effectively push a tag onto a stack which comprises local variables on
the C call stack, and then do a setjmp before executing the code being
protected, the tag contains the jmp_buf for setjmp, along with other
state needed for exception handling. Raising the exception does a
longjmp to the jmp_buf in the tag on the top of the stack, passing a
state which indicates that an exception is being raised.

The tag stack is also used for other purposes such as implementing
break, next, redo, and retry in loops.

Now I guess I could say that this "kind of" like an internal call, but
it's stretching things a bit further than I'd like

The break...end statement really just serves as a syntactic marker to
delimit where a series of statements being protected by
rescue/else/ensure starts, and where the last rescue/else/ensure ends.
If a begin..end sequence doesn't contain any rescue/ensure clauses, it
has no effect.

def..end also can mark those protected statements, although it also
serves the purpose of delimiting a method.

Now there might be a reason why the do..end, or {..} of a block can't
have the same feature, but I'm scratching my head to figure out why.
You CAN have a block which contains a single statement with a rescue
modifier:

   lambda do
        raise "help!" rescue "gotcha"
   end

is legal as is the semantically equivalent:

  lambda {raise "help!" rescue "gotcha"}

but

  lambda do
          raise "help!"
          rescue
                "gotcha"
  end

is not.

Perhaps someone else (Matz?) can enlighten me/us on why

-- Rick DeNatale

Now there might be a reason why the do..end, or {..} of a block can't
have the same feature, but I'm scratching my head to figure out why.
You CAN have a block which contains a single statement with a rescue
modifier:

   lambda do
        raise "help!" rescue "gotcha"
   end

is legal as is the semantically equivalent:

  lambda {raise "help!" rescue "gotcha"}

These two example illustrate the ability to attach a rescue modifier to a method call.
The fact that in these example the method calls are sitting by themselves inside
a block is irrelevant--the rescue is associated with the call and not with
the enclosing block. You can attach a rescue clause to any statement:

  (3/0) rescue "divide by zero"

  [1,2,3].map {|x| x/0 } rescue "divide by zero"

I think is important to view blocks as part of the syntax of a method call
in the same way that the period, parenthesis, and commas are part of the syntax
of a method call:

  receiver.method(arg1, arg2) { #code in a block }

So 'rescue', when it is attached to a single method call, is really part of the
syntax of the method call and the surrounding context is of no concern.
You can even have a rescue right in the middle of actual arguments:

  a = Array.new( 3/0 ) # raises ZeroDivisionError
  a = Array.new( (3/0 rescue 100) ) # creates an array with 100 entries

Note: I first tried that last example without the extra set of parens and the
parser didn't like it: Array.new( 3/0 rescue 100 ). Seems like an interesting
corner case on statement/expression parsing.

Anyway, my point is that rescue modifiers and their semantics are orthogonal to
block syntax (do/end {} ) and its semantics.

  lambda do
          raise "help!"
          rescue
                "gotcha"
  end

is not.

In this example, the rescue is *not* a modifier of the method call 'raise'. The
parser has fully processed the raise and is attempting to parse the next method call.
In that case rescue is not valid because do/end blocks do not open a new exception
context in the way that a method call or begin/end block do.

It might be easier to see what is going on from a parsing standpoint by substituting
semicolons for newlines:

lambda do
  raise "help!" rescue "gotcha" # one statement, a call to raise
end

lambda do
  raise "help!"; rescue "gotcha" # two statements, second one invalid
end

The method/statement modifier version of 'rescue' is syntactically different than
the version of 'rescue' attached to method definitions or begin/end blocks.

This may not have clarified the question regarding *why* do/end blocks don't
create a new exception scope but hopefully it clarifies the syntax associated with
a rescue modifier clause.

Gary Wright

···

On Sep 12, 2006, at 12:39 PM, Rick DeNatale wrote:

The journey is the reward!

···

On 9/12/06, Morton Goldberg <m_goldberg@ameritech.net> wrote:

Even without further explication, the above is already enlightening.
Thanks for taking the time and trouble to research this and write it up.

--
Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/

The OP is confused as to why the different semantics exist at all. It appears (to a newbie) to be very arbitrary. One pair of delimiters for a block being passed to a yield method or turned into a proc, another for a block with error trapping.

gwtmp01@mac.com wrote:

···

There is certainly a syntactic similarity to begin/end and do/end but why are the semantics of those particular pairs confusing?
Why stop there? You also have to deal with: module/end, class/end, def/end, if/end, case/end.

At some point you just have to realize that different syntactic blocks have different semantics and then learn the semantics.

--
Posted via a free Usenet account from http://www.teranews.com

Yes, I knew all that. I was trying to think of a semantic reason to
require wrapping exception handlers in a block inside a proc, when I
realized that a statement modifer gave some capability to do this as a
kind of degenerate case. The fact that you can have a block with a
single statement with a rescue modifier seems to weaken any argument
that you shouldn't be able to say

x.each do |a|
     statement 1
     statement 2
     rescue
         rescue-statement
     end

when you can say

   def meth(a)
         statement-1
         statement-2
         rescue
             rescue-statement
    end

It seems to be a purely syntactic restriction, with no semantic necessity.

I just searched RCRchive, and there's an existing RCR336 advocating
allowing rescue's in do..end blocks without requiring begin..end
inside. It seems like a good change to me, so I just voted for it.

But then I could be wrong.

···

On 9/13/06, gwtmp01@mac.com <gwtmp01@mac.com> wrote:

On Sep 12, 2006, at 12:39 PM, Rick DeNatale wrote:
> Now there might be a reason why the do..end, or {..} of a block can't
> have the same feature, but I'm scratching my head to figure out why.
> You CAN have a block which contains a single statement with a rescue
> modifier:
>
> lambda do
> raise "help!" rescue "gotcha"
> end
>
> is legal as is the semantically equivalent:
>
> lambda {raise "help!" rescue "gotcha"}

These two example illustrate the ability to attach a rescue modifier
to a method call.
The fact that in these example the method calls are sitting by
themselves inside
a block is irrelevant--the rescue is associated with the call and not
with
the enclosing block.

--
Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/

Rick DeNatale wrote:

You CAN have a block which contains a single statement with a rescue
modifier:

    lambda do
         raise "help!" rescue "gotcha"
    end

is legal as is the semantically equivalent:

   lambda {raise "help!" rescue "gotcha"}

but

   lambda do
           raise "help!"
           rescue
                 "gotcha"
   end

is not.

Perhaps someone else (Matz?) can enlighten me/us on why

I sure can't enlighten you, but I can comment: that is wierd! I must
admit that I didn't believe you at first, but I tried it, and sure
enough...you are correct. What the?! Wierd!!

Regards,
Jordan