Send() with a block?

Why don’t the ruby docs say that send() can take a block?

Kernel.send(:define_method, :my_meth) do |x|
puts x
end

my_meth(10)

–output:–
10

At the following link there is nothing saying that send() will accept a
block:

http://www.ruby-doc.org/core/classes/Object.html#M000999

Whereas, for example, at the following link it states that grep() will
take a block:

http://www.ruby-doc.org/core/classes/Enumerable.html#M001482

On Sat, Mar 12, 2011 at 8:45 PM, 7stud – [email protected]
wrote:

Why don’t the ruby docs say that send() can take a block?

Kernel.send(:define_method, :my_meth) do |x|
puts x
end

It’s not the send() that’s consuming the block - it’s the
define_method().

Regards,
Sean

On Sun, 13 Mar 2011 06:01:31 +0900, Sean O’Halpin wrote:

define_method().

But send() still bothers to pass the block around. Consider the
following code:

—8<—8<—
def my_method
p block_given?
end

def my_send # imitating send
my_method
end

my_send # => false
—8<—8<—

On Sat, Mar 12, 2011 at 9:11 PM, Peter Z. [email protected]
wrote:

I’m not sure what you’re showing me here. But consider this:

class Foo
def self.send(*a, &block)
p block_given?
super(*a)
end
end

class Bar
def self.send(*a)
p block_given?
super(*a)
end
end

Foo.send(:define_method, :my_method) do |x|
p x
end

block = proc{ |x| p x }
Bar.send(:define_method, :my_method2, &block)

foo = Foo.new
foo.my_method(1)
bar = Bar.new
bar.my_method2(2)

def my_method(x)
p x
end

my_method(10, &block)

END
true
true
1
2
10

Even when you explicitly do /not/ pass on the block (as in the
super(*a) call above), send() does not consume it.
Passing a block using the &block syntax is simply part of ruby’s
method calling syntax.
A method does not have to specify that it takes a block for you to
call it with one.

Regards,
Sean

On Mar 12, 2011, at 13:50 , Sean O’Halpin wrote:

A method does not have to specify that it takes a block for you to
call it with one.

Indeed… Take that statement a step further: ALL methods take a block,
they just don’t have to do anything with it:

% ruby -e ‘p 1.+(2) { p 42 }’
3

On Mar 12, 2011, at 12:45 , 7stud – wrote:

Why don’t the ruby docs say that send() can take a block?

From the pickaxe:

obj.send( symbol ⟨ , args ⟩∗ ⟨ , &block ⟩ ) → other_obj

ALL methods take a block, they just don’t have to do anything with it

One of the best replies. And beautifully signifies the flexible approach
taken by Ruby.

Blocks rule.

Peter Z. wrote in post #987115:

On Sun, 13 Mar 2011 06:01:31 +0900, Sean O’Halpin wrote:

define_method().

But send() still bothers to pass the block around. Consider the
following code:

—8<—8<—
def my_method
p block_given?
end

def my_send # imitating send
my_method
end

my_send # => false
—8<—8<—

But compare with this:

def my_method
p block_given?
end

def my_send(&blk) # imitating send
my_method(&blk)
end

my_send # => false
my_send { :wibble } # => true

On Sun, 13 Mar 2011 23:26:01 +0900, Brian C. wrote:

p block_given?

def my_method
p block_given?
end

def my_send(&blk) # imitating send
my_method(&blk)
end

my_send # => false
my_send { :wibble } # => true

That’s the whole point of my demonstration. (Maybe I was too concise.)
Any send-like method should to a trick like that to get the
block-passing
behavior. It is not implicit.

On Sun, Mar 13, 2011 at 2:54 PM, Peter Z. [email protected]
wrote:

following code:
my_send # => false
end

my_send # => false
my_send { :wibble } # => true

That’s the whole point of my demonstration. (Maybe I was too concise.)

You were so concise you left out the thing you were trying to
demonstrate:

def my_send
p block_given?
end

my_send { p 42 } #=> true

Any send-like method should to a trick like that to get the block-passing
behavior. It is not implicit.

It /is/ implicit and is true for any method call. That’s how you can do
this:

def my_yield
yield
end

my_yield { p 42 } #=> 42

You specify the &block parameter when you want to do something with the
block.

Regards,
Sean

Peter Z. wrote in post #987191:

That’s the whole point of my demonstration. (Maybe I was too concise.)
Any send-like method should to a trick like that to get the
block-passing
behavior. It is not implicit.

Indeed. And the O.P. was passing a block to send explicitly too.

On 12.03.2011 22:50, Sean O’Halpin wrote:

end

end
Even when you explicitly do /not/ pass on the block (as in the
super(*a) call above), send() does not consume it.

Automatic propagation of the block is not a feature of #send but a
feature of “super”:

class X
def a;p block_given? end
def b;p block_given?;a end
def c;p block_given?;send(:a) end
end
=> nil

X.new.a {1+2}
true
=> true

X.new.b {1+2}
true
false
=> false

X.new.c {1+2}
true
false
=> false

class A
def a;p block_given? end
end
=> nil

class B < A
def a;p block_given?;super end
end
=> nil

class C < A
def a;p block_given?;super() end
end
=> nil

A.new.a {1+2}
true
=> true

B.new.a {1+2}
true
true
=> true

C.new.a {1+2}
true
true
=> true

Passing a block using the&block syntax is simply part of ruby’s
method calling syntax.
A method does not have to specify that it takes a block for you to
call it with one.

Correct.

Kind regards

robert

Or to put it another way:

def my_method
p block_given?
end

def my_send # imitating send
my_method
end

my_send # => false
my_send { :wibble } # => false

def my_send_2
send :my_method
end

my_send_2 # => false
my_send_2 { :wibble } # => false

It’s entirely consistent: false in all four cases.

The actual method “send” can take a block, and it passes it to the
method being invoked. If it didn’t, it would be impossible to pass a
block to a method when invoking it using send.

On Sun, Mar 13, 2011 at 11:40 PM, Aaron D. Gifford
removed_email_addre[email protected]wrote:

I agree that the documentation the original post linked to really
should mention that if any block is passed to send, the block is
passed on to the method invoked.

Based on Robert’s code, isn’t this false, with it being a feature of
super
and not send?

On Sun, Mar 13, 2011 at 11:00 AM, Brian C. [email protected]
wrote:

The actual method “send” can take a block, and it passes it to the
method being invoked. If it didn’t, it would be impossible to pass a
block to a method when invoking it using send.

I agree that the documentation the original post linked to really
should mention that if any block is passed to send, the block is
passed on to the method invoked.

From the linked docs: “Invokes the method identified by symbol,
passing it any arguments specified. You can use send if the name send
clashes with an existing method in obj.”

That could use an additional sentence: “If a block is supplied to
send, the block is supplied to the method invoked.”

Aaron out.

On Sat, Mar 12, 2011 at 2:45 PM, 7stud – [email protected]
wrote:


Posted via http://www.ruby-forum.com/.

It says “Invokes the method identified by symbol, passing it any
arguments
specified.” A block is an argument, it just gets set into an implicit
location by default, or you can make it explicit, putting it into a Proc
object, by putting &varname on the end of your params list.

I’ve had difficulty following the code examples in this thread. Here is
the
one I think is relevant:

def meth(first, second=12 , *rest, &block)
[first , second , rest , block]
end

send :meth , 1 # => [1, 12, [], nil]
send :meth , 1 , 2 # => [1, 2, [], nil]
send :meth , 1 , 2 , 3 # => [1, 2, [3], nil]
send :meth , 1 , 2 , 3 do end # => [1, 2, [3],
#Proc:[email protected]:8]

You can see, it passes on ordinal arguments, args with default values,
variable lengthed arguments, and yes, also blocks.

On Mar 13, 2011, at 8:00 PM, Adam P. wrote:

On Sun, Mar 13, 2011 at 11:40 PM, Aaron D. Gifford [email protected]wrote:

I agree that the documentation the original post linked to really
should mention that if any block is passed to send, the block is
passed on to the method invoked.

Based on Robert’s code, isn’t this false, with it being a feature of super
and not send?

No. Robert’s code with super certainly demonstrated that super will
propagate a block but that is entirely beside the point because send
doesn’t use super to invoke the named method. I really don’t understand
why Robert said:

Automatic propagation of the block is not a feature of #send but a feature of
“super”:

Internally #send is written to propagate any block to the named method
and that should be documented.

Gary W.

On Sun, Mar 13, 2011 at 10:47 PM, Aaron D. Gifford
[email protected]wrote:

Correct, a block IS an argument, but of a rather unusual type in that
it may or may not be explicit in the definition of a method that uses
it.

There is always a block slot, as Ryan said “ALL methods take a block”.
What
is explicit is whether or not you wish to assign it to a named object.
Even
then, you can turn the implicit block into a Proc object, if you need.

def meth
proc.call
end

meth { 1 + 1 } # => 2

When I read documents and see a method that does NOT explicitly

mention a block, I assume that it will NOT pass any supplied block on
to yet another method.

Hence, I expect that the send() documentation really should mention
that any block passed to it IS passed through to the method specified
as the first argument to send().

This is really all you needed to say. I think all your code detracted
from
this point.

On Mon, Mar 14, 2011 at 1:27 AM, Gary W. [email protected] wrote:

Based on Robert’s code, isn’t this false, with it being a feature of super
and not send?

No. Robert’s code with super certainly demonstrated that super will propagate a
block but that is entirely beside the point because send doesn’t use super to
invoke the named method. I really don’t understand why Robert said:

Automatic propagation of the block is not a feature of #send but a feature of
“super”:

My point was, that automatic propagation (i.e. propagation without
the user needing to do something) is only done by “super” (please see
the example). All other delegating mechanisms (i.e. directly calling
a method, invoking #send) do need to explicit propagate the block.
And #send likely does so internally as well - although I tend to view
#send less as a method but rather as a language feature of Ruby’s
reflection capabilities.

Internally #send is written to propagate any block to the named method and that
should be documented.

Yes, of course. Method #send without block propagation would render
it pretty much useless since any method in Ruby can use a block.

Kind regards

robert

On Sun, Mar 13, 2011 at 8:30 PM, Josh C. [email protected]
wrote:

It says “Invokes the method identified by symbol, passing it any arguments
specified.” A block is an argument…

Correct, a block IS an argument, but of a rather unusual type in that
it may or may not be explicit in the definition of a method that uses
it.

HOWEVER, if a method (call it method bar or baz) passes any block it
receives on to yet another method (call it method foo), it is best
that the documents include this fact.

AN EXAMPLE:

Method foo() may or may not be given a block…

def foo(*args)
puts “foo(#{args.inspect}) called with” + (block_given? ? ‘’ :
‘out’) + " a block included."
yield *args if block_given?
end

Method bar() does NOT explicitly capture block arguments

and thus does NOT pass any given block on to foo():

def bar(*args)
puts “bar(#{args.inspect}) called with” + (block_given? ? ‘’ :
‘out’) + " a block included."
foo(*args)
end

Method baz() DOES explicitly capture block arguments

and DOES pass any given block on to foo():

def baz(*args, &block)
puts “baz(#{args.inspect}) called with” + (block_given? ? ‘’ :
‘out’) + " a block included."
foo(*args, &block)
end

bar(“some”, :args => “for bar”, :without => “a block”)
puts
bar(“some”, :args => “for bar”, :with => “a block”) { |*a| puts “block
passed to bar(): #{a.inspect}” }
puts “–”
baz(“some”, :args => “for baz”, :without => “a block”)
puts
baz(“some”, :args => “for baz”, :with => “a block”) { |*a| puts “block
passed to baz(): #{a.inspect}” }

SAMPLE OUTPUT FROM ABOVE EXAMPLE:
bar([“some”, {:args=>“for bar”, :without=>“a block”}]) called without
a block included.
foo([“some”, {:args=>“for bar”, :without=>“a block”}]) called without
a block included.

bar([“some”, {:args=>“for bar”, :with=>“a block”}]) called with a
block included.
foo([“some”, {:args=>“for bar”, :with=>“a block”}]) called without a
block included.

baz([“some”, {:args=>“for baz”, :without=>“a block”}]) called without
a block included.
foo([“some”, {:args=>“for baz”, :without=>“a block”}]) called without
a block included.

baz([“some”, {:args=>“for baz”, :with=>“a block”}]) called with a
block included.
foo([“some”, {:args=>“for baz”, :with=>“a block”}]) called with a
block included.
block passed to baz(): [“some”, {:args=>“for baz”, :with=>“a block”}]

THINGS TO NOTE FROM THE EXAMPLE:

  • Notice that even though bar() uses the splat to capture and pass
    through all supplied arguments, because it does NOT explicitly include
    a &block argument, it does NOT automatically pass through any provided
    block.=
  • Note that baz() DOES explicitly include a &block argument and
    explicitly passes it through.

When I read documents and see a method that does NOT explicitly
mention a block, I assume that it will NOT pass any supplied block on
to yet another method.

Hence, I expect that the send() documentation really should mention
that any block passed to it IS passed through to the method specified
as the first argument to send().

Maybe I’m eccentric, but I prefer that documentation for a method
which uses a block, either directly or by passing it through to
another method, whether the block is explicit or implicit in the
method definition, to clearly document what the block is used for or
what is done with it.

Aaron out.

This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.

| Privacy Policy | Terms of Service | Remote Ruby Jobs