send() with a block?

S

Sean O'Halpin

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

Kernel.send:)define_method, :my_meth) do |x|
=A0puts x
end

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

Regards,
Sean
 
P

Peter Zotov

It's not the send() that's consuming the block - it's the
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<---
 
S

Sean O'Halpin

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

---8<---8<---
def my_method
=A0p block_given?
end

def my_send # imitating send
=A0my_method
end

my_send # =3D> false
---8<---8<---

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 =3D proc{ |x| p x }
Bar.send:)define_method, :my_method2, &block)

foo =3D Foo.new
foo.my_method(1)
bar =3D 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
 
R

Ryan Davis

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

=46rom the pickaxe:

obj.send( symbol =E2=9F=A8 , args =E2=9F=A9=E2=88=97 =E2=9F=A8 , &block =
=E2=9F=A9 ) =E2=86=92 other_obj=
 
R

Ryan Davis

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
 
M

Marc Heiler

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.
 
R

Robert Klemme

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.

Automatic propagation of the block is not a feature of #send but a
feature of "super":
true
=> truetrue
false
=> falsetrue
false
=> false

true
=> truetrue
true
=> truetrue
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
 
B

Brian Candler

Peter Zotov wrote in post #987115:
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
 
P

Peter Zotov

Peter Zotov wrote in post #987115:

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

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.
 
S

Sean O'Halpin

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 } #=3D> 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 thi=
s:

def my_yield
yield
end

my_yield { p 42 } #=3D> 42

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

Regards,
Sean
 
B

Brian Candler

Peter Zotov 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.
 
B

Brian Candler

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.
 
A

Aaron D. Gifford

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.
 
A

Adam Prescott

[Note: parts of this message were removed to make it a legal post.]

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?
 
G

Gary Wright

=20
=20
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 Wright=
 
J

Josh Cheek

[Note: parts of this message were removed to make it a legal post.]

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

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:0x00000100868340@-:8>]


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

Aaron D. Gifford

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.
 
J

Josh Cheek

[Note: parts of this message were removed to make it a legal post.]

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.
 
R

Robert Klemme

No. =A0Robert's code with super certainly demonstrated that super will pr=
opagate a block but that is entirely beside the point because send doesn't =
use super to invoke the named method. =A0I really don't understand why Robe=
rt said:re 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 an=
d 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

--=20
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,770
Messages
2,569,583
Members
45,074
Latest member
StanleyFra

Latest Threads

Top