What does it mean to yield within a block?
Basically if the current method has been given a code-block (by the caller, when it was invoked), the yield
executes the code block passing in the specified parameters.
[1,2,3,4,5].each { |x| puts x }
Now { |x| puts x}
is the code-block (x
is a parameter) passed to the each method of Array
. The Array#each
implementation would iterate over itself and call your block multiple times with x = each_element
pseudocode
def each
#iterate over yourself
yield( current_element )
end
Hence it results
1
2
3
4
5
The *block_args
is a Ruby way to accept an unknown number of parameters as an array. The caller can pass in blocks with different number of arguments.
Finally let's see what yield within a block does.
class MyClass
def print_table(array, &block)
array.each{|x| yield x}
end
end
MyClass.new.print_table( [1,2,3,4,5] ) { |array_element|
10.times{|i| puts "#{i} x #{array_element} = #{i*array_element}" }
puts "-----END OF TABLE----"
}
Here Array#each
yields each element to the block given to MyClass#print_table
...
Is it safe to yield from within a with block in Python (and why)?
I don't really understand what conflict you're asking about, nor the problem with the example: it's fine to have two coexisting, independent handles to the same file.
One thing I didn't know that I learned in response to your question it that there is a new close() method on generators:
close()
raises a newGeneratorExit
exception inside the generator to terminate the iteration. On receiving this exception, the generator’s code must either raiseGeneratorExit
orStopIteration
.
close()
is called when a generator is garbage-collected, so this means the generator’s code gets one last chance to run before the generator is destroyed. This last chance means thattry...finally
statements in generators can now be guaranteed to work; thefinally
clause will now always get a chance to run. This seems like a minor bit of language trivia, but using generators andtry...finally
is actually necessary in order to implement thewith
statement described by PEP 343.http://docs.python.org/whatsnew/2.5.html#pep-342-new-generator-features
So that handles the situation where a with
statement is used in a generator, but it yields in the middle but never returns—the context manager's __exit__
method will be called when the generator is garbage-collected.
Edit:
With regards to the file handle issue: I sometimes forget that there exist platforms that aren't POSIX-like. :)
As far as locks go, I think Rafał Dowgird hits the head on the nail when he says "You just have to be aware that the generator is just like any other object that holds resources." I don't think the with
statement is really that relevant here, since this function suffers from the same deadlock issues:
def coroutine():
lock.acquire()
yield 'spam'
yield 'eggs'
lock.release()
generator = coroutine()
generator.next()
lock.acquire() # whoops!
Yielding inside a block
Proper functioning of the included Enumerable
interface's methods requires that the class implement an each
method that yields successive values. The implementation in your sample code effectively delegates this logic to that of Array
's each method (since @players
is an Array).
Replacing yield
with return
would result in no values being provided, and bypassing any code block that was passed in.
You could experiment with the each
implementation to verify this.
Ruby: the yield inside of a block
The block is passed similarly to the argument of that function. This can be specified explicitly, like so:
class Test
def my_each(&block)
"abcdeabcabc".scan("a") do |x|
puts "!!! block"
yield x
# Could be replaced with: block.call(x)
end
end
end
Technically, it's exactly the same (puts
put in there for clarification), its presence is not checked the way it is usually done for arguments. Should you forget to give it a block, the function will halt on the first yield
it has to execute with exactly the same LocalJumpError
(at least, that's what I get on Rubinius). However, notice the "!!! block" in the console before it happens.
It works like that for a reason. You could check whether your function is given a block, if it is specified explicitly as above, using if block
, and then skip the yield
s. A good example of that is a content_tag
helper for Rails. Calls of this helper can be block-nested. A simplistic example:
content_tag :div do
content_tag :div
end
...to produce output like:
<div>
<div></div>
</div>
So, the block is executed "on top" (in terms of call stack) of your method. It is called each time a yield
happens as some sort of function call on a block. It's not accumulated anywhere to execute the block afterwards.
UPD:
The Enumerator
returned by many each
es is explicitly constructed by many iterators to save context of what should happen.
It could be implemented like this on my_each
:
class Test
def my_each(&block)
if block
"abcdeabcabc".scan("a") { |x| yield x }
else
Enumerator.new(self, :my_each)
end
end
end
Blocks and yields in Ruby
Yes, it is a bit puzzling at first.
In Ruby, methods can receive a code block in order to perform arbitrary segments of code.
When a method expects a block, you can invoke it by calling the yield
function.
Example:
Take Person
, a class with a name
attribute and a do_with_name
method. When the method is invoked it will pass the name
attribute to the block.
class Person
def initialize( name )
@name = name
end
def do_with_name # expects a block
yield( @name ) # invoke the block and pass the `@name` attribute
end
end
Now you can invoke this method and pass an arbitrary code block.
person = Person.new("Oscar")
# Invoking the method passing a block to print the value
person.do_with_name do |value|
puts "Got: #{value}"
end
Would print:
Got: Oscar
Notice the block receives as a parameter a variable called value
. When the code invokes yield
it passes as argument the value of @name
.
yield( @name )
The same method can be invoked with a different block.
For instance to reverse the name:
reversed_name = ""
# Invoke the method passing a different block
person.do_with_name do |value|
reversed_name = value.reverse
end
puts reversed_name
=> "racsO"
Other more interesting real life examples:
Filter elements in an array:
days = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"]
# Select those which start with 'T'
days.select do | item |
item.match /^T/
end
=> ["Tuesday", "Thursday"]
Or sort by name length:
days.sort do |x,y|
x.size <=> y.size
end
=> ["Monday", "Friday", "Tuesday", "Thursday", "Wednesday"]
If the block is optional you can use:
yield(value) if block_given?
If is not optional, just invoke it.
You can try these examples on your computer with irb
(Interactive Ruby Shell)
Here are all the examples in a copy/paste ready form:
class Person
def initialize( name )
@name = name
end
def do_with_name # expects a block
yield( @name ) # invoke the block and pass the `@name` attribute
end
end
person = Person.new("Oscar")
# Invoking the method passing a block to print the value
person.do_with_name do |value|
puts "Got: #{value}"
end
reversed_name = ""
# Invoke the method passing a different block
person.do_with_name do |value|
reversed_name = value.reverse
end
puts reversed_name
# Filter elements in an array:
days = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"]
# Select those which start with 'T'
days.select do | item |
item.match /^T/
end
# Sort by name length:
days.sort do |x,y|
x.size <=> y.size
end
Trouble yielding inside a block/lambda
Lambdas don't implicitly accept blocks like regular methods do, so your func1
can't yield. Do this instead:
func1 = lambda do |x, &blk|
for i in 1 .. 5
blk.call(x * i)
end
end
Specifically, I believe this is because yield would send control back to the caller
's block, which would not include lambda invocations. So the following code works like you "expect":
def foo
(lambda { |n| yield(n) }).call(5)
end
foo { |f| puts f } # prints 5
yield inside with block in python function
Because you aren't actually iterating over the generator:
You have something similar to this in your code:
doSmth() # simply creates generator without advancing it
without the for x in doSmth()
What does 'yield called out of block' mean in Ruby?
The problem is that the times method expects to get a block that it will yield control to. However you haven't passed a block to it. There are two ways to solve this. The first is to not use times:
mySet = (1..numOfCuts).map{ rand(seqLength) }
or else pass a block to it:
mySet = []
numOfCuts.times {mySet.push( rand(seqLength) )}
Yield within Set to eliminate in an Array
In Ruby, when you are putting yield
keyword inside any method(say #bar
), you are explicitly telling #bar
that, you will be using a block with the method #bar
. So yield
knows, inside the method block will be converted to a Proc
object, and yield
have to call that Proc
object.
Example :
def bar
yield
end
p bar { "hello" } # "hello"
p bar # bar': no block given (yield) (LocalJumpError)
In the
uniq_by
method, we did not do anything to handle block argument. How is the passed argument handled byuniq_by
method?
You did do, that is you put yield
. Once you will put this yield
, now method is very smart to know, what it supposed to so. In the line Messages.all.uniq_by { |h| h.body }
you are passing a block { |h| h.body }
, and inside the method definition of uniq_by
, that block has been converted to a Proc
object, and yield
does Proc#call
.
Proof:
def bar
p block_given? # true
yield
end
bar { "hello" } # "hello"
Better for understanding :
class Array
def uniq_by
seen = Set.new
select{ |x| seen.add?( yield( x ) ) }
end
end
is same as
class Array
def uniq_by
seen = Set.new
# Below you are telling uniq_by, you will be using a block with it
# by using `yield`.
select{ |x| var = yield(x); seen.add?(var) }
end
end
Read the doc of yield
Called from inside a method body, yields control to the code block (if any) supplied as part of the method call. If no code block has been supplied, calling
yield
raises an exception.yield
can take an argument; any values thus yielded are bound to the block's parameters. The value of a call toyield
is the value of the executed code block.
Related Topics
How to Listen to Stdin Input Without Pausing My Script
How to Click a Link in a Table Based on the Text in a Row
Cron Is Running in Home Directory Instead of File Directory
Shortening Socket Timeout Using Timeout::Timeout(N) Does Not Seem to Work for Me
Unable to Delete File from Amazon S3 Using Ruby Script
Using Ruby and Mechanize to Fill in a Remote Login Form Mystery
Algorithm to Print All Valid Combations of N Pairs of Parenthesis
Multipart Response in Ruby/Rack
How to Run an Excel MACro from Ruby
Ruby Class Object Garbage Collection
How to Mock Super in Ruby Using Rspec
Ruby How to Merge Two CSV Files with Slightly Different Headers
Store Image in Database Using Rails Paperclip Plugin
Why Does Hash#Select and Hash#Reject Pass a Key to a Unary Block