How is the proc object stored in `&` -` & `roundtrip?

When I pass an array with * when passing it to the method, and then restore the array from it using * inside the method, the array identifier is not saved:

 a = [] a.object_id # => 69846339548760 def bar *a; a.object_id end bar(*a) # => 69846339537540 

However, when I pass the proc to the block with & when passing it to the method, then restore the proc from the block using & inside the method, the identity of the proc seems to be preserved:

 pr = ->{} pr.object_id # => 69846339666160 def foo ≺ pr.object_id end foo(&pr) # => 69846339666160 

How is the proc object stored? Is it not lost when it is converted to a block? Is this guaranteed behavior?

+5
source share
1 answer

Ruby VM is a static machine. When calling a function, it pushes all its arguments (including self ) onto the stack and then calls.

How the splat array works - it takes the contents of the array and puts it on the stack, and then calls the function:

 > puts RubyVM::InstructionSequence.compile("a = []; func *a").disasm == disasm: <RubyVM::InstructionSequence:<compiled>@<compiled>>========== local table (size: 2, argc: 0 [opts: 0, rest: -1, post: 0, block: -1, kw: -1@-1 , kwrest: -1]) [ 2] a 0000 trace 1 ( 1) 0002 newarray 0 0004 setlocal_OP__WC__0 2 0006 putself 0007 getlocal_OP__WC__0 2 0009 splatarray false 0011 opt_send_without_block <callinfo!mid:func, argc:1, ARGS_SPLAT|FCALL> 0013 leave 

When transferring proc in the form of a block, a similar situation occurs, but the ruby ​​does not need to deploy proc, it is already proc.

Added: according to RubySpec https://github.com/ruby/spec/blob/master/core/proc/block_pass_spec.rb

 def revivify; Proc.new; end it "remains the same object if re-vivified by the target method" do p = Proc.new {} p2 = revivify(&p) p.object_id.should == p2.object_id p.should == p2 end 

this is somewhat standardized behavior, so at least Rubinius and jRuby should be followed

+2
source

Source: https://habr.com/ru/post/1241800/


All Articles