Proc.class vs yield 
Author Message
 Proc.class vs yield

Hi,
        I'm a Smalltalk programmer and I have to say, of what I've seen of Ruby
I'm impressed. I like it. Except for one inconsistency which really
drives me up the wall. Two objects that nearly do the same thing, Proc
and Block? { someCode } - one you send yield to, the other you send call.

Why?! That means you have to know what kind of object you have before
you can send the message to it.

Michael Lucas-Smith



Fri, 18 Jun 2004 09:11:05 GMT  
 Proc.class vs yield
Hi,

At Mon, 31 Dec 2001 10:21:07 +0900,

Quote:

>    I'm a Smalltalk programmer and I have to say, of what I've seen of Ruby
> I'm impressed. I like it. Except for one inconsistency which really
> drives me up the wall. Two objects that nearly do the same thing, Proc
> and Block? { someCode } - one you send yield to, the other you send call.

Block is a Proc.

--
Nobu Nakada



Fri, 18 Jun 2004 10:05:55 GMT  
 Proc.class vs yield
Hello --

Quote:

> Hi,
> I'm a Smalltalk programmer and I have to say, of what I've seen of
> Ruby

Welcome to Ruby!

Quote:
> I'm impressed. I like it. Except for one inconsistency which really
> drives me up the wall. Two objects that nearly do the same thing, Proc
> and Block? { someCode } - one you send yield to, the other you send call.

> Why?! That means you have to know what kind of object you have before
> you can send the message to it.

Well, the only time you would use yield is in an iterator, when you
want to yield control to the block associated with the method call
(and get back the result).  You don't exactly send yield to the block;
that is, yield is not a method.

You'd want to send "call" to a Proc object.  Normally there shouldn't
be any ambiguity about this.  If you've got a reference to something
in a variable, it's a Proc.

You can convert a block to a Proc with "proc" (aka "lambda").  Also,
when a block is supplied to a method, you can capture that block,
converted to a Proc object, with the &var syntax in the param list.
You can then call that Proc:

  def some_iterator(&b)
    # b now refers to the given block
    # Call it five times:
    5.times {|i| b.call(i) }
  end

  some_iterator {|i| puts i}

The more usual way to do it would be:

  def some_iterator
    5.times {|i| yield i}
  end

that is, just letting control bounce back and forth, courtesy of
yield.

David

--
David Alan Black


Web:  http://pirate.shu.edu/~blackdav



Fri, 18 Jun 2004 10:11:15 GMT  
 Proc.class vs yield

Quote:

> Hi,
>         I'm a Smalltalk programmer and I have to say, of what I've seen of Ruby
> I'm impressed. I like it. Except for one inconsistency which really
> drives me up the wall. Two objects that nearly do the same thing, Proc
> and Block? { someCode } - one you send yield to, the other you send call.

> Why?! That means you have to know what kind of object you have before
> you can send the message to it.

Actually, I don't think that blocks are objects at all, until you use
#proc or Proc.new to make a Proc instance using the block. (You can also
use the & argument prefix to do this.)

I've always assumed that blocks denote a piece of code plus an argument
list plus a binding, but without wrapping these things up into an
object. Maybe it's more efficient to do it this way?



Fri, 18 Jun 2004 10:27:14 GMT  
 Proc.class vs yield

Quote:

>   def some_iterator(&b)
>     # b now refers to the given block
>     # Call it five times:
>     5.times {|i| b.call(i) }
>   end

>   some_iterator {|i| puts i}

Aha! Thanks. This is exactly what I was looking for. Except it's not
as.. well, nice. More syntax candy to do the job that the language could
do intuitively otherwise.

None the less, this is good :)

Michael.



Fri, 18 Jun 2004 11:02:31 GMT  
 Proc.class vs yield

Quote:
> I've always assumed that blocks denote a piece of code plus an argument
> list plus a binding, but without wrapping these things up into an
> object. Maybe it's more efficient to do it this way?

I suspect you're right. In Smalltalk, every bit of code inside the [] is
another object. They're always all full block closures. I have no idea
what this does to the performance.

Michael.



Fri, 18 Jun 2004 11:03:14 GMT  
 Proc.class vs yield
def someThing (&a, &b)

this gives me a parse error:

./tst.rb:3: parse error
def blah (&a, &b)



Fri, 18 Jun 2004 11:12:50 GMT  
 Proc.class vs yield
Hi --

Quote:

> def someThing (&a, &b)

> this gives me a parse error:

> ../tst.rb:3: parse error
> def blah (&a, &b)

The & variable has a special status: there can only be one, it has to
be last in the list, and it grabs the block (which otherwise can be
"yield"ed to but can't be referenced).

So typically you'd see:

  def my_method(arg1, arg2, &block)
    ...
  end

I'm not sure what you want to do in your example....  What are you
expecting &a and &b to be?

David

--
David Alan Black


Web:  http://pirate.shu.edu/~blackdav



Fri, 18 Jun 2004 11:31:06 GMT  
 Proc.class vs yield
Quote:

>So typically you'd see:

>  def my_method(arg1, arg2, &block)
>    ...
>  end

>I'm not sure what you want to do in your example....  What are you
>expecting &a and &b to be?

Two proc's. It seems that I can't pass two procs to a method unless the
calling method is horribly ugly.

Michael



Fri, 18 Jun 2004 11:47:02 GMT  
 Proc.class vs yield
Hi --

Quote:

> >So typically you'd see:

> >  def my_method(arg1, arg2, &block)
> >    ...
> >  end

> >I'm not sure what you want to do in your example....  What are you
> >expecting &a and &b to be?

> Two proc's. It seems that I can't pass two procs to a method unless the
> calling method is horribly ugly.

Passing Proc objects is inherently no uglier than passing any other
kind:

  pr1 = proc { |x| puts "My arg is #{x}" }
  pr2 = proc { |x| puts "My arg * 2 is #{x * 2}" }
  some_method(pr1,pr2)

Neither of those procs, though, is the method call's block.  You'd
have to specify that too, if you want to use one:

  some_method(pr1,pr2) { puts "This is the supplied block." }

David

--
David Alan Black


Web:  http://pirate.shu.edu/~blackdav



Fri, 18 Jun 2004 12:29:37 GMT  
 Proc.class vs yield

Quote:
----- Original Message -----


Sent: Sunday, December 30, 2001 9:46 PM
Subject: [ruby-talk:29797] Re: Proc.class vs yield

> >So typically you'd see:

> >  def my_method(arg1, arg2, &block)
> >    ...
> >  end

> >I'm not sure what you want to do in your example....  What are you
> >expecting &a and &b to be?

> Two proc's. It seems that I can't pass two procs to a method unless the
> calling method is horribly ugly.

You can pass a proc just like any other object
(without the ampersand)... the & notation grabs
the block that is specified with the method call,
and (as they said in _Highlander_) there can be
only one.

But as ordinary parameters, you can pass any
number of Proc objects...

Hal Fulton



Fri, 18 Jun 2004 13:20:56 GMT  
 Proc.class vs yield

Quote:

> Hi --


>>>So typically you'd see:

>>> def my_method(arg1, arg2, &block)
>>>   ...
>>> end

>>>I'm not sure what you want to do in your example....  What are you
>>>expecting &a and &b to be?

>>Two proc's. It seems that I can't pass two procs to a method unless the
>>calling method is horribly ugly.

> Passing Proc objects is inherently no uglier than passing any other
> kind:

>   pr1 = proc { |x| puts "My arg is #{x}" }
>   pr2 = proc { |x| puts "My arg * 2 is #{x * 2}" }
>   some_method(pr1,pr2)

> Neither of those procs, though, is the method call's block.  You'd
> have to specify that too, if you want to use one:

>   some_method(pr1,pr2) { puts "This is the supplied block." }

> David

The reason I'm bringing this up is because having a criteria block of
code and a failure block of code si very common in Smalltalk. For example:

childrenOf: aPersonName in: people
people
        detect: [:person | person name = aPersonName]
        ifFound: [:person | person children]
        ifNone: [OrderedCollection new]

in normal ST-80, this might be written as:

childrenOf: aPersonName in: people
| namedPerson |
(namedPerson :=
        people
                detect: [:person | person name = aPersonName]
                ifNone: [nil]) isNil
                        ifTrue: [OrderedCollection new]
                        ifFalse: [namedPerson children]

The standard ST-80 comes with lots of two-block methods to make things
easy for you. I add a few three-block methods.

As you can surely see, the first three-block example is easier to read
than the two-block example.

A one block example might be something along the lines of:

def childrenOf (aPersonName, people)
        if (namedPerson := people.detect { |person| person.name = aPersonName }) then
                return namedPerson.children
        else
                return Array.new
        end
end

I'm not really too fussed on how easily one can be written or the other,
but what I am interested in is readability. The first three-block
example does exactly what it says.

The second two-block example is harder to read because ST-80 normally
exceptions when detect: fails, thus you have to call detect:ifNone:.

The one-block Ruby example takes advantage of the true/false nil/not-nil
tricks, but is still not as readable as the three-block example.

What I'm really trying to point out is, it's a real shame that you are
forced to add this 'proc' thing before your blocks of code. To do
something similar to the three-block example in Ruby you'd have:

def childrenOf (aPersonName, people)
        return people.detect proc { |person| person.name = aPersonName },
                proc { |person| person.children},
                proc { Array.new }
end

When really, I want to be able to write:

def childrenOf (aPersonName, people)
        return people.detect
                { |person| person.name = aPersonName },
                { |person| person.children },
                { Array.new }
end

But there are two things stopping me.
(1) The parser spits at having the first argument start on the second line
(2) I need to explicitely say they're procs.

Michael



Fri, 18 Jun 2004 13:19:48 GMT  
 Proc.class vs yield

Quote:

> The reason I'm bringing this up is because having a criteria block of
> code and a failure block of code si very common in Smalltalk

I wonder whether your failure block could be replaced by the
throwing and catching of an exception?  I realise, of course,
that the standard containers don't tend to throw exceptions
in this case.  However, if you would like this behaviour, you
might be able to either derive your own classes from them, or
use Ruby's dynamic facilities to modify the behaviour of the
containers themselves.

Just a thought ... and someone else who knows how things work
in ST  may be able to clean it up to make it more palatable.



Fri, 18 Jun 2004 13:45:05 GMT  
 Proc.class vs yield

Quote:


>>The reason I'm bringing this up is because having a criteria block of
>>code and a failure block of code si very common in Smalltalk

> I wonder whether your failure block could be replaced by the
> throwing and catching of an exception?  I realise, of course,
> that the standard containers don't tend to throw exceptions
> in this case.  However, if you would like this behaviour, you
> might be able to either derive your own classes from them, or
> use Ruby's dynamic facilities to modify the behaviour of the
> containers themselves.

> Just a thought ... and someone else who knows how things work
> in ST  may be able to clean it up to make it more palatable.

I may be mistaken, but it appears as though the exception throwing and
catching is global within your namespace? when I read 'catch' and
'throw' in the reference manuals for 1.4, they don't seem to talk about
a scope at all.

Otherwise, you could end up writing some code along the lines of:

def childrenOf (aPersonName, people)
        catch (:found) { |person| return person.children }
        catch (:none) { return Array.new }
        people.detect { |person| person.name = aPersonName }
end

but now the method is backwards and counter intuitive.

Michael



Fri, 18 Jun 2004 13:54:22 GMT  
 Proc.class vs yield
Slight amendment to the code:
Quote:

> def childrenOf (aPersonName, people)
>     catch (:found) { |person| person.children }
>     catch (:none) { Array.new }
>     return people.detect { |person| person.name = aPersonName }
> end



Fri, 18 Jun 2004 13:57:39 GMT  
 
 [ 55 post ]  Go to page: [1] [2] [3] [4]

 Relevant Pages 

1. Difference between proc.call and yield?

2. block , yield and proc?

3. Can't yield from Proc

4. block.call vs. yield

5. Understanding code: 100 classes vs. 5000 classes

6. Understanding code: 100 classes vs. 5000 classes

7. Access to T'Class vs T'Class as parameter to subprogram

8. new-style classes VS classic-classes

9. itcl::class vs class

10. CLASS & PROC Type

11. module_eval: adding a method to a class with a proc

12. CAN AN ASM PROC BE A CLASS MEMBER ?

 

 
Powered by phpBB® Forum Software