Using 'return' in a Ruby block - ruby

I'm trying to use Ruby 1.9.1 for an embedded scripting language, so that "end-user" code gets written in a Ruby block. One issue with this is that I'd like the users to be able to use the 'return' keyword in the blocks, so they don't need to worry about implicit return values. With this in mind, this is the kind of thing I'd like to be able to do:
def thing(*args, &block)
value = block.call
puts "value=#{value}"
end
thing {
return 6 * 7
}
If I use 'return' in the above example, I get a LocalJumpError. I'm aware that this is because the block in question is a Proc and not a lambda. The code works if I remove 'return', but I'd really prefer to be able to use 'return' in this scenario. Is this possible? I've tried converting the block to a lambda, but the result is the same.

Simply use next in this context:
$ irb
irb(main):001:0> def thing(*args, &block)
irb(main):002:1> value = block.call
irb(main):003:1> puts "value=#{value}"
irb(main):004:1> end
=> nil
irb(main):005:0>
irb(main):006:0* thing {
irb(main):007:1* return 6 * 7
irb(main):008:1> }
LocalJumpError: unexpected return
from (irb):7:in `block in irb_binding'
from (irb):2:in `call'
from (irb):2:in `thing'
from (irb):6
from /home/mirko/.rvm/rubies/ruby-1.9.1-p378/bin/irb:15:in `<main>'
irb(main):009:0> thing { break 6 * 7 }
=> 42
irb(main):011:0> thing { next 6 * 7 }
value=42
=> nil
return always returns from method, but if you test this snippet in irb you don't have method, that's why you have LocalJumpError
break returns value from block and ends its call. If your block was called by yield or .call, then break breaks from this iterator too
next returns value from block and ends its call. If your block was called by yield or .call, then next returns value to line where yield was called

You cannot do that in Ruby.
The return keyword always returns from the method or lambda in the current context. In blocks, it will return from the method in which the closure was defined. It cannot be made to return from the calling method or lambda.
The Rubyspec demonstrates that this is indeed the correct behaviour for Ruby (admittedly not a real implementation, but aims full compatibility with C Ruby):
describe "The return keyword" do
# ...
describe "within a block" do
# ...
it "causes the method that lexically encloses the block to return" do
# ...
it "returns from the lexically enclosing method even in case of chained calls" do
# ...

I admire the answer of s12chung. Here is my little improvement of his answer. It lets avoid cluttering the context with method __thing.
def thing(*args, &block)
o = Object.new
o.define_singleton_method(:__thing, block)
puts "value=#{o.__thing}"
end
thing { return 6 * 7 }

You are looking it from the wrong point of view.
This is an issue of thing, not the lambda.
def thing(*args, &block)
block.call.tap do |value|
puts "value=#{value}"
end
end
thing {
6 * 7
}

I had the same issue writing a DSL for a web framework in ruby... (the web framework Anorexic will rock!)...
anyway, I dug into the ruby internals and found a simple solution using the LocalJumpError returned when a Proc calls return... it runs well in the tests so far, but I'm not sure it's full-proof:
def thing(*args, &block)
if block
block_response = nil
begin
block_response = block.call
rescue Exception => e
if e.message == "unexpected return"
block_response = e.exit_value
else
raise e
end
end
puts "value=#{block_response}"
else
puts "no block given"
end
end
the if statement in the rescue segment could probably look something like this:
if e.is_a? LocalJumpError
but it's uncharted territory for me, so I'll stick to what I tested so far.

I found a way, but it involves defining a method as an intermediate step:
def thing(*args, &block)
define_method(:__thing, &block)
puts "value=#{__thing}"
end
thing { return 6 * 7 }

Where is thing invoked? Are you inside a class?
You may consider using something like this:
class MyThing
def ret b
#retval = b
end
def thing(*args, &block)
implicit = block.call
value = #retval || implicit
puts "value=#{value}"
end
def example1
thing do
ret 5 * 6
4
end
end
def example2
thing do
5 * 6
end
end
end

I believe this is the correct answer, despite the drawbacks:
def return_wrap(&block)
Thread.new { return yield }.join
rescue LocalJumpError => ex
ex.exit_value
end
def thing(*args, &block)
value = return_wrap(&block)
puts "value=#{value}"
end
thing {
return 6 * 7
}
This hack allows users to use return in their procs without consequences, self is preserved, etc.
The advantage of using Thread here is that in some cases you won't get the LocalJumpError - and the return will happen in the most unexpected place (onside a top-level method, unexpectedly skipping the rest of it's body).
The main disadvantage is the potential overhead (you can replace the Thread+join with just the yield if that's enough in your scenario).

Related

Running a Ruby Proc in class scope

I've been scratching my head over how to add behaviour to a specific instance
of a class in Ruby. If I use instance_exec like below however the method that calls the proc does not execute all of the way through.
class HasSecret
def initialize(x)
#secret = x
end
def doTheThing(&block)
puts "before block"
instance_exec(#secret, &block)
puts "after block"
end
end
foo = HasSecret.new(5)
foo.doTheThing do |x|
puts "x"
return x
end
This example simply gives:
before block
5
Is there any perscribed approach to doing this?
Try this:
foo.doTheThing do |x|
puts x
end
Generally, you are not supposed to return in blocks. Calling return in a block will cause the method yielding (enclosing) to return, which is usually not the behaviour desired. It can also case a LocalJumpError.
In fact, because this scenario is so nuanced and uncommon, a lot of people say you can't return from a block. Check out the conversation in the comments of the answer on this question, for example: Unexpected Return (LocalJumpError)
In your case, you aren't seeing the "after block" puts because the return in the passed block is causing doTheThing to return before getting there.

implicit block passed gives local jump error

def my_function(&block)
p block.call #1
# lambda{return "inside the block"}.call #2
end
p my_function{return "implicit block"}
Why is line 1 giving a LocalJumpError(Its saying unexpected return)?
Although according to me line 1 and line 2 are basically the same thing.The block variable here is a proc object and so is a lambda.
Shouldn't they also behave the same. line 2 once uncommented doesn't seem to give an error
#Andre
def my_function(&block)
p block.call #1
# lambda{return "inside the block"}.call #2
end
def abc
p my_function{return "implicit block"}
end
abc
Shouldn't this work?
There are many differences between Lambda and Proc, as you can see in this post for example.
One of them is how the return behaves in each case.
When you return in a Proc, it will return from the method it is being called.
And when you return in a Lambda it returns only to outside the lambda code.
The reason for the LocalJumpError is simply because you are you're calling return probably from your ruby console and there is no enclosing method to return. So if you surround your code with a method and call it, it will work.
def test
def my_function(&block)
p block.call
end
p my_function{ return "implicit block" }
end
test
=> "implicit block"
def my_function(&block)
p block.call #1
# lambda{return "inside the block"}.call #2
end
p my_function{return "implicit block"}
Why is line 1 giving a LocalJumpError(Its saying unexpected return)?
A block (and a Proc) return from their enclosing methods. In your example, there is no enclosing method (the block literal is at the top-level), therefore there is nothing to return from.
Lambdas OTOH return from themselves, just like methods.
def my_function(&block)
p block.call #1
# lambda{return "inside the block"}.call #2
end
def abc
p my_function{return "implicit block"}
end
abc
Shouldn't this work?
Yes, it should, and it does.
For completeness' sake: there are two differences between methods / lambdas and blocks / Procs:
Blocks and Procs return from their enclosing methods, lambdas and methods return from themselves.
Blocks and Procs use loose argument binding with semantics that are similar to assignment (in fact, prior to Ruby 1.9, they used assignment semantics), lambdas and methods use strict argument binding.
Here's a kind-of stupid mnemonic I use: "block" and Proc rhyme and they behave the same, "method" and "lambda" are both Greek words and they behave the same.

How to pass blocks between methods?

I have two methods which both except a block, however one of the methods needs to pass its block to the other.
def one(&block)
two(block)
end
def two(&block)
block.call
end
In the real code other parameters are passed and one is syntax sugar over two.
I want to be able to call both one and two with a block.
one { } # => okay
two { } # => ArgumentError: wrong number of arguments (1 for 0)
I can see why I get the ArgumentError, two takes no argument as such. I'm not quite sure how to phrase this but &block designates the block appears after the passed in arguments, hence the error.
Ruby 1.9
You could just pass the &block to your second method like so:
def one(&block)
two(&block)
end
def two(&block)
block.call
end
one { puts "Hello World" }
Hello World
#=> nil
Update
You could also do something like this
def one
two(&Proc.new)
end
def two(&block)
block.call
end
It will have the same output as above. Do note that if no block is given to one, it will raise an ArgumentError: tried to create Proc object without a block so you'd have to check if the block is given by calling if block_given?
You could do the same with yield:
def one
two { yield }
end
def two
yield
end

A method that applies self to a proc

I want to have a method defined on Object that takes a block and applies the receiver to the block. An implementation will be like the following:
class Object
def apply &pr; pr.call(self) end
end
2.apply{|x| x * 3} # => 6
Is there already a standard way to do this or a well known library that has a method with similar use? If so, I didn't want to reinvent the wheel.
It happens to me very often that, I have a method that takes an optional block, and when there is no block, I want to return some return_value calculated within the method, but when there is a block, I want to return the return value of the return_value applied to the block. For now, I have bunches of lines like:
def method ..., &pr
...
pr ? pr.call(return_value) : return_value
end
but I want to consistently write
def method ..., &pr
...
pr ? return_value.apply(&pr) : return_value
end
or even better, with a slightly modified definition of apply,
def method ..., &pr
...
return_value.apply(&pr)
end
I guess Object.tap is what you are looking for:
"Abc".tap do |str|
puts str
end
Is that not identical to def apply; yield self; end? – steenslag
#steenslag Yes. It is. I want to have that effect with self as the receiver. – sawa
Is this what you mean?
2.instance_eval { * 3 }
# => 6
Unfortunately, that doesn't work. instance_eval simply runs code as if the receiver was self. Operators don't presume self as the receiver, so you'd actually have to write this:
2.instance_eval { self * 3 }
# => 6
However, as a proof of concept, this is possible:
Numeric.send(:define_method, :plus) { |x| self + x }
2.instance_eval { plus 3 }
# => 5
(Aftwer reading OP's edit) AFAIK the canonical way to write this is:
def purpose(*args) #no &bl or &pr
res = 42 #huge calculation
return res unless block_given?
yield res
end
p purpose(1,2)
purpose{|n| puts "from the block: #{n}"}

how to pass a Ruby iterator as a parameter?

I'd like to write a method that yields values in one place and pass it as a parameter to another method that will invoke it with a block. I'm convinced it can be done but somehow I'm not able to find the right syntax.
Here's some sample (non-working) code to illustrate what I'm trying to achieve:
def yielder
yield 1
yield 2
yield 3
end
def user(block)
block.call { |x| puts x }
end
# later...
user(&yielder)
$ ruby x.rb
x.rb:2:in `yielder': no block given (yield) (LocalJumpError)
from x.rb:12:in `<main>'
FWIW, in my real code, yielder and user are in different classes.
Update
Thanks for your answers. As Andrew Grimm mentioned, I want the iterator method to take parameters. My original example left this detail out. This snippet provides an iterator that counts up to a given number. To make it work, I made the inner block explicit. It does what I want, but it's a bit ugly. If anyone can improve on this I'd be very interested in seeing how.
def make_iter(upto)
def iter(upto, block)
(1 .. upto).each do |v|
block.call(v)
end
end
lambda { |block| iter(upto, block) }
end
def user(obj)
obj.call Proc.new { |x| puts x }
end
# later...
user(make_iter(3))
This doesn't use a lambda or unbound method, but it is the simplest way to go...
def f
yield 1
yield 2
end
def g x
send x do |n|
p n
end
end
g :f
When you write &yielder, you're calling yielder and then trying to apply the & (convert-to-Proc) operator on the result. Of course, calling yielder without a block is a no-go. What you want is to get a reference to the method itself. Just change that line to user(method :yielder) and it will work.
I think this might be along the lines of what you want to do:
def yielder
yield 1
yield 2
yield 3
end
def user(meth)
meth.call { |x| puts x }
end
# later...
user( Object.method(:yielder) )
Some related info here: http://blog.sidu.in/2007/11/ruby-blocks-gotchas.html
As it has been pointed out the baseline problem is that when you try to pass a function as a parameter Ruby executes it – as a side effect of parenthesis being optional.
I liked the simplicity of the symbol method that was mentioned before, but I would be afraid of my future self forgetting that one needs to pass the iterator as a symbol to make that work. Being readability a desired feature, you may then wrap your iterator into an object, which you can pass around without fear of having code unexpectedly executed.
Anonymous object as iterator
That is: using an anonymous object with just one fuction as iterator. Pretty immediate to read and understand. But due to the restrictions in the way Ruby handles scope the iterator cannot easily receive parameters: any parameters received in the function iterator are not automatically available within each.
def iterator
def each
yield("Value 1")
yield("Value 2")
yield("Value 3")
end
end
def iterate(my_iterator)
my_iterator.each do |value|
puts value
end
end
iterate iterator
Proc object as iterator
Using a Proc object as iterator lets you easily use any variables passed to the iterator constructor. The dark side: this starts looking weird. Reading the Proc.new block is not immediate for the untrained eye. Also: not being able to use yield makes it a bit uglier IMHO.
def iterator(prefix:)
Proc.new { |&block|
block.call("#{prefix} Value 1")
block.call("#{prefix} Value 2")
block.call("#{prefix} Value 3")
}
end
def iterate(my_iterator)
my_iterator.call do |value|
puts value
end
end
iterate iterator(prefix: 'The')
Lambda as iterator
Ideal if you want to obfuscate your code so hard that no one else besides you can read it.
def iterator(prefix:)
-> (&block) {
block.call("#{prefix} Value 1")
block.call("#{prefix} Value 2")
block.call("#{prefix} Value 3")
}
end
def iterate(my_iterator)
my_iterator.call do |value|
puts value
end
end
iterate iterator(prefix: 'The')
Class as iterator
And finally the good ol' OOP approach. A bit verbose to initialize for my taste, but with little or none surprise effect.
class Iterator
def initialize(prefix:)
#prefix = prefix
end
def each
yield("#{#prefix} Value 1")
yield("#{#prefix} Value 2")
yield("#{#prefix} Value 3")
end
end
def iterate(my_iterator)
my_iterator.each do |value|
puts value
end
end
iterate Iterator.new(prefix: 'The')

Resources