Why no yield in 1.9.2 blocks?

Hi,

I searched in vain for the answer, but why doesn’t yield work inside
Ruby 192 blocks. The syntax allows you to pass the blocks as a &blk
param, but you have to call the block with blk.call. If you try to use
yield, you get a LocalJumpError:

ruby-1.9.2-p0 > l= lambda {|&blk| yield}
=> #<Proc:0x000001009d4ad0@(irb):2 (lambda)>
ruby-1.9.2-p0 > l.call {puts 1}
LocalJumpError: no block given (yield)
from (irb):2:in block in irb_binding' from (irb):3:in call’
from (irb):3
from /Users/edh/.rvm/rubies/ruby-1.9.2-p0/bin/irb:17:in `’

But this works:

ruby-1.9.2-p0 > l= lambda {|&blk| blk.call}
=> #<Proc:0x000001009dc910@(irb):4 (lambda)>
ruby-1.9.2-p0 > l.call {puts 1}
1
=> nil

At least it agrees with block_given?

ruby-1.9.2-p0 > l=lambda {|&blk| puts “block given” if block_given?;
puts “done”}
=> #<Proc:0x00000101825f30@(irb):6 (lambda)>
ruby-1.9.2-p0 > l.call
done
=> nil
ruby-1.9.2-p0 > l.call {puts 1}
done
=> nil

I can live with block.call instead of yield, but no block_given?

Why would you want to pass a block to a block? Why not? so you can do
things like:

def meth(x, &block)
if block_given?
block.call(x) do |y|
puts "in meth " + y.to_s
end
end
end

ruby-1.9.2-p0 > meth(1) {|x, &blk| puts "in blok " + x.to_s; blk.call 2}
in blok 1
in meth 2

[Note, trying this with yield leads to a SyntaxError.]

Cheers,
Ed

Ed Howland

http://twitter.com/ed_howland

On Oct 22, 3:09pm, Ed Howland [email protected] wrote:

LocalJumpError: no block given (yield)
from (irb):2:in block in irb_binding' from (irb):3:in call’
from (irb):3
from /Users/edh/.rvm/rubies/ruby-1.9.2-p0/bin/irb:17:in `’

irb(main):002:0> p = proc{|&blk| yield}
=> #Proc:0x02833540@:2(irb)
irb(main):003:0> p.call{puts 1}
LocalJumpError: no block given
from (irb):2
from (irb):3:in `call’
from (irb):3
from :0
irb(main):004:0> VERSION
=> “1.8.7”

On 22.10.2010 22:09, Ed Howland wrote:

I searched in vain for the answer, but why doesn’t yield work inside
Ruby 192 blocks. The syntax allows you to pass the blocks as a&blk
param, but you have to call the block with blk.call. If you try to use
yield, you get a LocalJumpError:

This isn’t something new in 1.9.2. There is no version of Ruby that I
am aware of that would allow this.

ruby-1.9.2-p0> meth(1) {|x,&blk| puts "in blok " + x.to_s; blk.call 2}
in blok 1
in meth 2

There are also other useful usecases for this, namely defining methods
with a block dynamically

in some class

define_method :foo do |x,y,&b|
puts “before”
yield # or b.call
puts “after”
end

Kind regards

robert

On Fri, Oct 22, 2010 at 3:09 PM, Ed Howland [email protected]
wrote:

Hi,

I searched in vain for the answer, but why doesn’t yield work inside
Ruby 192 blocks. The syntax allows you to pass the blocks as a &blk
param, but you have to call the block with blk.call. If you try to use
yield, you get a LocalJumpError:

I always figured it was because it was enclosing its environment, and
having
yield in the block and the environment could bet ambiguous.

def sort_proxy(collection)
collection.sort! do |a,b|
yield a , b # yield in a block
end
end

ary = [4,2,9,3,1]

sort_proxy ary do |a,b|
a <=> b
end

ary # => [1, 2, 3, 4, 9]

Josh C. wrote in post #956495:

I always figured it was because it was enclosing its environment, and
having
yield in the block and the environment could bet ambiguous.

Yes, I believe that’s the case. Consider:

def foo # <- block passed implicitly
bar do |&baz|
yield 123 # <- invokes the outer block
end
end

I think of ‘yield’ like ‘return’. ‘yield’ invokes the block passed in to
the enclosing method, and ‘return’ returns from the enclosing method.