Project

General

Profile

Bug #13774

for methods defined from procs, the binding of the resulting bound_method.to_proc does not have access to the original proc's closure environment

Added by bughit (bug hit) about 2 years ago. Updated over 1 year ago.

Status:
Rejected
Priority:
Normal
Assignee:
-
Target version:
-
ruby -v:
ruby 2.5.0p0 (2017-12-25 revision 61468) [x86_64-linux]
[ruby-core:82200]

Description

def foo
  o = Object.new
  local_var = 'local_var'
  method_lambda = ->{local_var}
  o.define_singleton_method(:lambda_method, &method_lambda)
  method_proc = o.method(:lambda_method).to_proc
  puts method_proc.()
  puts eval('local_var', method_lambda.binding)
  puts o.lambda_method
  puts eval('local_var', method_proc.binding) # undefined local variable or method `local_var'
end

foo

when executed as a method it has access to local_var as expected
but the binding of the bound method proc does not

in ruby 2.2.2 the above code crashes the vm

History

Updated by bughit (bug hit) about 2 years ago

bughit (bug hit) wrote:

def foo
  o = Object.new
  local_var = 'local_var'
  method_lambda = ->{local_var}
  o.define_singleton_method(:lambda_method, &method_lambda)
  method_proc = o.method(:lambda_method).to_proc
  puts method_proc.()
  puts eval('local_var', method_lambda.binding)
  puts o.lambda_method
  puts eval('local_var', method_proc.binding) # undefined local variable or method `local_var'
end

foo

when executed as a method it has access to local_var as expected
but the binding of the bound method proc does not

in ruby 2.2.2 the above code crashes the vm

should also underscore that the bound method proc has access to local_var: method_proc.()
but its binding does not eval('local_var', method_proc.binding), so there's a clear discrepancy between a proc and its binding

Updated by bughit (bug hit) over 1 year ago

  • ruby -v changed from ruby 2.4.1p111 (2017-03-22 revision 58053) [x86_64-linux] to ruby 2.5.0p0 (2017-12-25 revision 61468) [x86_64-linux]
  • Subject changed from for methods defined from procs, the binding of the resulting bound method proc does not have access to the original proc's closure environment to for methods defined from procs, the binding of the resulting bound_method.to_proc does not have access to the original proc's closure environment
def foo
  o = Object.new
  local_var = 'has access to captured variable'

  original_proc = ->{local_var}

  o.define_singleton_method(:method_from_proc, &original_proc)
  method_proc = o.method(:method_from_proc).to_proc

  puts "original_proc.call #{original_proc.()}"
  puts "original_proc.binding #{original_proc.binding.eval('local_var')}"

  puts "#method_from_proc #{o.method_from_proc}"

  puts "method(:method_from_proc).to_proc.call #{method_proc.()}"
  puts "method(:method_from_proc).to_proc.binding #{method_proc.binding.eval('local_var') rescue "does not have access to captured variable: #{$!.inspect}"}"

end

foo

method(:method_from_proc).to_proc.binding does not have access to captured variable: #<NameError: undefined local variable or methodlocal_var'`

This is a bug?

Updated by nobu (Nobuyoshi Nakada) over 1 year ago

I think it is not a bug.

Local variables are not set up in the context of a binding from a method.

$ ruby -e 'def m(v=12);v;end; p method(:m).to_proc.binding.eval("v")'
Traceback (most recent call last):
    2: from -e:1:in `<main>'
    1: from -e:1:in `eval'
-e:1:in `<empty iseq>': undefined local variable or method `v' for main:Object (NameError)

Updated by bughit (bug hit) over 1 year ago

nobu (Nobuyoshi Nakada) wrote:

I think it is not a bug.

Local variables are not set up in the context of a binding from a method.

$ ruby -e 'def m(v=12);v;end; p method(:m).to_proc.binding.eval("v")'
Traceback (most recent call last):
  2: from -e:1:in `<main>'
  1: from -e:1:in `eval'
-e:1:in `<empty iseq>': undefined local variable or method `v' for main:Object (NameError)

You are accessing a local variable in the method (which does not exist until the method is invoked), whereas I am accessing a variable outside the method, captured by the proc that defined the method, which does exist outside the invocation of the method. So your example does not explain the behavior that I am highlighting.

To try answer my own question, I can see how this might not be a bug if method.to_proc returns a proc that is no way related to the proc that defined the method. Such a proc simply forwards the args to the method and knows nothing about the original proc binding. I initially thought that it would somehow inherit the binding of the original proc.

Updated by nobu (Nobuyoshi Nakada) over 1 year ago

Once a Proc is bound as a method, the context of that method is not same as the based Proc, receiver for instance.

x = ->{}
o = Object.new
o.define_singleton_method(:x, x)
p x.binding.receiver #=> main
p o.method(:x).to_proc.binding.receiver #=> o
#6

Updated by nobu (Nobuyoshi Nakada) over 1 year ago

  • Status changed from Open to Rejected

Also available in: Atom PDF