I am looking at some code that is roughly:
foo = true
while foo
foo = newfoo() do
thing1()
end
end
What is going on here? What does the do
... end
block that follows the foo
assignment do?
I am looking at some code that is roughly:
foo = true
while foo
foo = newfoo() do
thing1()
end
end
What is going on here? What does the do
... end
block that follows the foo
assignment do?
It's a block. In Ruby exists blocks, procs and lambdas. Check this link to understand it better.
http://www.reactive.io/tips/2008/12/21/understanding-ruby-blocks-procs-and-lambdas/
What you see is do...end block being passed to a function BEFORE assignment is being made. Remember code:
[1,2].each do puts "xd" end
? Block "do puts "xd" end" is passed here to the "each" method.
Same in your code.
The newfoo() function is being called with the block, the block is assumably yielded in newfoo() and then return value of newfoo() is assigned to foo.
You should however avoid such syntax, if the block is short- use {} instead of do..end, if it's not - consider using Proc.new instead.
Two code examples for you, both with the same result:
def newfoo()
yield()
return false
end
foo = true
while(foo)
foo = newfoo() do
puts "JP2GMD"
end
end
And version with storing Proc
truth_to_be_spoken = Proc.new { puts "JP2GMD" }
def newfoo()
yield()
return false
end
foo = true
while(foo)
foo = newfoo() {truth_to_be_spoken.call()}
end
Edit in response to comment
"{}" is certainly not preferable to "do ...end" in any other case than really short proc being passed (which was the case in example).
To why would you want to use proc instead of passing result parameter in real situations (note this are just examples to show syntax, not the real-world uses!): there are many reasons, now i can think of at least two simple examples:
1. You can use it to evaluate something lazily inside your function only if needed:
magic_number = Proc.new do
x = # some really complicated code
# it posts question on stackoverflow
# to ask users, what number they would like to divide
# waits an hour for answers
# and picks the one with most votes
return x
end
def divide_numbers(divisor)
if divisor == 0
puts "Cannot into"
else
dividend = yield
puts (dividend / divisor)
end
You can use values that will be known inside function and pass them as parameters (which is in fact, how you use iteration methods!). Here is the code that uses that two times - parameter is passed with each to a block "{}" and inside "{}" you pass a parameter to a declared proc:
second_power_double_printer = Proc.new do |param| puts param puts param end
[1,2,3,4].each { |number| double_printer.call(number*number) }
To why use do..end/{} syntax instead of passing block as parameter. There might be more reasons i can't think of right know, but
Do...end / {} will implicitly create anonymous block for you. You can't do it with parameter, for example:
def f(proc) proc.call() end
f(do puts "It's sad:(" end)
If you use anonymous blocks you can make at least one mistake - forget to pass a block. If you use function parameters you can make at least two mistakes - forget to pass anything (although - if you're using IDE it would help you in this case) and pass something, that is not a block - resulting in "undefined method call" error.