Bugs: Browse | Submit New | Admin

[#10598] return from block inside a lambda does not work as expected

Date:
2007-05-05 03:00
Priority:
3
Submitted By:
Jeff Reinecke (paploo)
Assigned To:
Yukihiro Matsumoto (matz)
Category:
Language / Runtime / Core Libraries
State:
Open
Platform:
 
Summary:
return from block inside a lambda does not work as expected

Detailed description
As I understand it, a lambda block is different than a Proc.new block in that return works like it does in functions,
allowing you to essentially create inline anonymous functions that have access to the variable scope in which it is
defined.  (This is great for some complex algorithms).

When trying to use this functionality with a lambda function that, inside of it had several levels of iteration utilizing
Range#each, I found that doing a return from within any of the blocks used by Range#each would return the whole top
level function, not just the lambda.

This is inconsistent with both what I'd expect, and what return does if it is used anywhere else in a labmda block.


As an example, please consider the following trivial and highly contrived example.  A call to foo returns out of the
defined lambda block m, assigning the variable q and returning from foo properly, when v is negative.  However, if v
is positive and the iteration over the range is executed, the return returns from both m and foo, skipping the assignment
to q and the further processing that foo does to that result, and instead returns n straight out of foo.  (I bet that
was hard to follow)  :)


def foo(value)
  m = lambda do |v|
    return "v is negative" if v < 0
      (5...100).each do |n|
        #This line returns from the whole method, not just from the block!
        return n if v.modulo(n).zero?
      end
    return false
  end
  
  q = m.call(value)
  return "ANSWER: #{q.inspect}"
end

Add A Comment: Notepad

Please login


Followup

Message
Date: 2007-09-21 19:48
Sender: Florian Pflug

I've taken a look at the code now - It seems that this behaviour
is not happend by accident, but on purpose.

When return_jump() (in eval.c) scans the enclosing contexts,
it seems to explicitly set a flag when encountering a YIELD context,
and later ingores any LAMBDA contexts it finds should that flag
be set.

That makes me wonder - Why should one want a return directly
inside a lambda to work, but than want it to fail when wrapped
inside another block?
Date: 2007-09-21 19:03
Sender: Florian Pflug

It seems that the target that a "return" would jump
to gets setup correctly by lambda, but is reset when entering
another block inside the lambda. I stumbled upon the same bug,
only that it manifests itself as a "LocalJumpError"
in my case - probably because I did return the lambda from the
function, and called it later. Therefore the (wrong) target that
the return wants to jump to is orphaned in my case, and
a LocalJumpError is raised.
Date: 2007-06-12 05:28
Sender: Shyouhei Urabe

Assigning to matz as this can be a design matter.

Attached Files:

Name Description Download
No Files Currently Attached

Changes:

Field Old Value Date By
assigned_toshyouhei2007-06-12 05:28shyouhei
assigned_tonone2007-06-12 02:24zenspider
category_idMisc / Other Standard Library2007-05-29 21:16zenspider
category_idLanguage / Runtime / Core Libraries2007-05-29 15:55zenspider