Backport #8341

block_given? (and the actual block) persist between calls to a proc created from a method (using method().to_proc()).

Added by Joshua Yanovski 12 months ago. Updated 10 months ago.

[ruby-core:54626]
Status:Closed
Priority:Normal
Assignee:Usaku NAKAMURA

Description

Confirmed on both 2.0.0 and 1.9.2-p290. A testcase (utilizing RSpec) is attached, but the behavior is easy to demonstrate without a testcase or RSpec.

First, we define a method that can optionally accept a block.
def foo
if block_given?
yield
else
puts "No block given."
end
end

Then, we convert the method to a proc and store it in a variable.
methodtoproc = method(:foo).to_proc

Now, we try calling methodtoproc without a block, getting the expected result:
methodtoproc.call
# => No block given.

We call it again, this time with a block, and again get the expected result:
methodtoproc.call { puts "Block given." }
# => Block given.

But when we call it a third time, again with no block...
methodtoproc.call
# => Block given.
...it remembers the previous proc that was passed in.

If we then call it with a new proc, it overwrites the old proc as expected (this is not tested in the testcase, which only tests blockgiven?):
method
to_proc.call { puts "New block given." }
# => New block given.

The testcase verifies this behavior, and also that the behavior does not occur when calling a method in the usual way, or when using method() but not toproc(), or when using method().toproc() but not storing the result in the same variable (the last of which isn't that surprising but is included for completeness).

I cannot see any reason that this should be expected behavior. Either blockgiven? should work the same way in method.toproc()s as it does in method()s, or it should always return false, and it certainly shouldn't "remember" the last block used.

testcase.rb Magnifier (1.67 KB) Joshua Yanovski, 04/28/2013 06:32 AM

8341.patch Magnifier (2.32 KB) Kazuki Tsujimoto, 06/16/2013 03:29 AM


Related issues

Related to Backport93 - Backport #8531: ifuncに渡したブロックが共有される Closed 06/16/2013

Associated revisions

Revision 41650
Added by Usaku NAKAMURA 10 months ago

merge revision(s) 41342,41359,41361: [Backport #8341]

test/ruby/test_proc.rb: tests for [Bug #8341]
* include/ruby/intern.h, proc.c (rb_method_call_with_block):
  new function to invoke a Method object with a block passed
  as an argument.

* proc.c (bmcall): use the above function to avoid a block sharing.
   [Bug #8341]

* test/ruby/test_proc.rb (TestProc#test_block_persist_between_calls):
  run related tests.

* test/ruby/test_proc.rb (TestProc#test_block_given_method_to_proc):
  run test for r41359.

History

#1 Updated by Kazuki Tsujimoto 10 months ago

  • File 8341.patchMagnifier added
  • Assignee set to Koichi Sasada

bmcall'(ifunc) should use a block set byvmyieldwithcfunc' instead of PASSEDBLOCK.
I attached a patch.

#2 Updated by Nobuyoshi Nakada 10 months ago

  • Category set to core
  • Assignee changed from Koichi Sasada to Kazuki Tsujimoto

LTGM

#3 Updated by Nobuyoshi Nakada 10 months ago

  • Status changed from Open to Assigned

#4 Updated by Nobuyoshi Nakada 10 months ago

  • Status changed from Assigned to Closed
  • % Done changed from 0 to 100

This issue was solved with changeset r41342.
Joshua, thank you for reporting this issue.
Your contribution to Ruby is greatly appreciated.
May Ruby be with you.


test/ruby/test_proc.rb: tests for [Bug #8341]

#5 Updated by Nobuyoshi Nakada 10 months ago

  • Status changed from Closed to Assigned
  • % Done changed from 100 to 0
  • Backport changed from 1.9.3: UNKNOWN, 2.0.0: UNKNOWN to 1.9.3: REQUIRED, 2.0.0: REQUIRED

#6 Updated by Kazuki Tsujimoto 10 months ago

  • Status changed from Assigned to Closed
  • % Done changed from 0 to 100

This issue was solved with changeset r41359.
Joshua, thank you for reporting this issue.
Your contribution to Ruby is greatly appreciated.
May Ruby be with you.


  • include/ruby/intern.h, proc.c (rbmethodcallwithblock):
    new function to invoke a Method object with a block passed
    as an argument.

  • proc.c (bmcall): use the above function to avoid a block sharing.
    [Bug #8341]

  • test/ruby/testproc.rb (TestProc#testblockpersistbetween_calls):
    run related tests.

#7 Updated by Kazuki Tsujimoto 10 months ago

  • Tracker changed from Bug to Backport
  • Project changed from ruby-trunk to Backport200
  • Category deleted (core)
  • Status changed from Closed to Assigned
  • Assignee changed from Kazuki Tsujimoto to Tomoyuki Chikanaga

Please backport r41342, r41359.

#8 Updated by Kazuki Tsujimoto 10 months ago

Oops, r41361 is also needed.

#9 Updated by Tomoyuki Chikanaga 10 months ago

  • Status changed from Assigned to Closed

This issue was solved with changeset r41392.
Joshua, thank you for reporting this issue.
Your contribution to Ruby is greatly appreciated.
May Ruby be with you.


merge revision(s) 41342,41359,41361: [Backport #8341]

test/ruby/test_proc.rb: tests for [Bug #8341]
* include/ruby/intern.h, proc.c (rb_method_call_with_block):
  new function to invoke a Method object with a block passed
  as an argument.

* proc.c (bmcall): use the above function to avoid a block sharing.
   [Bug #8341]

* test/ruby/test_proc.rb (TestProc#test_block_persist_between_calls):
  run related tests.

* test/ruby/test_proc.rb (TestProc#test_block_given_method_to_proc):
  run test for r41359.

#10 Updated by Tomoyuki Chikanaga 10 months ago

  • Project changed from Backport200 to Backport93
  • Status changed from Closed to Assigned
  • Assignee changed from Tomoyuki Chikanaga to Usaku NAKAMURA

#11 Updated by Usaku NAKAMURA 10 months ago

  • Status changed from Assigned to Closed

This issue was solved with changeset r41650.
Joshua, thank you for reporting this issue.
Your contribution to Ruby is greatly appreciated.
May Ruby be with you.


merge revision(s) 41342,41359,41361: [Backport #8341]

test/ruby/test_proc.rb: tests for [Bug #8341]
* include/ruby/intern.h, proc.c (rb_method_call_with_block):
  new function to invoke a Method object with a block passed
  as an argument.

* proc.c (bmcall): use the above function to avoid a block sharing.
   [Bug #8341]

* test/ruby/test_proc.rb (TestProc#test_block_persist_between_calls):
  run related tests.

* test/ruby/test_proc.rb (TestProc#test_block_given_method_to_proc):
  run test for r41359.

Also available in: Atom PDF