How is Proc#==
evaluated? RDoc says:
prc == other_proc → true or false
Returns true if prc is the same object as other_proc, or if they are both procs with the same body.
But it is not clear what counts as having "the same body". One condition seems to be that the arity must be the same:
->{} == ->{} # => true
->{} == ->x{} # => false
->x{} == ->x{} # => true
->x{} == ->y{} # => true
->x{} == ->y,z{} # => false
But there is more than that. As RDoc says, the body matters:
->{nil} == ->{nil} # => true
->{nil} == ->{false} # => false
->{false} == ->{false} # => true
But at the same time, it looks like the proc is not fully evaluated:
->{} == ->{nil} # => false
->{false} == ->{1 == 2} # => false
To what extent is the body evaluated?
Proc file system (procfs) is virtual file system created on fly when system boots and is dissolved at time of system shut down. It contains useful information about the processes that are currently running, it is regarded as control and information center for kernel.
The proc file system acts as an interface to internal data structures in the kernel. It can be used to obtain information about the system and to change certain kernel parameters at runtime (sysctl).
proc is a special file system and is not associated with any hard drive device. Certian files inside /proc can be modified to change the behaviour of a running kernel. For example, /proc/sys/ files. Most of the system monitoring commands like ps, top, free, etc use process files inside /proc/ to fetch information.
The Linux /proc File System is a virtual filesystem that exists in RAM (i.e., it is not stored on the hard drive). That means that it exists only when the computer is turned on and running.
This has changed in Ruby 2.0, so you should not try to compare Proc
s. They won't be ==
unless they are exactly the same object.
The discussion can be found here.
If you really need to compare the code of two blocks and are using MRI, you can play around with RubyVM::InstructionSequence.disassemble(block)
, or even better in Ruby 2.0 RubyVM::InstructionSequence.of(block)
.
To answer that question lets look at the proc comparison code
static VALUE
proc_eq(VALUE self, VALUE other)
{
if (self == other) {
return Qtrue;
}
else {
if (rb_obj_is_proc(other)) {
rb_proc_t *p1, *p2;
GetProcPtr(self, p1);
GetProcPtr(other, p2);
if (p1->envval == p2->envval &&
p1->block.iseq->iseq_size == p2->block.iseq->iseq_size &&
p1->block.iseq->local_size == p2->block.iseq->local_size &&
MEMCMP(p1->block.iseq->iseq, p2->block.iseq->iseq, VALUE,
p1->block.iseq->iseq_size) == 0) {
return Qtrue;
}
}
}
return Qfalse;
}
The first if branch is quite simple - compare it two procs are the same object. The second is little bit more tricky. It checks that both of the procs have same envval, size of the iseq(proc implementation), local variables size and compares that the both implementations are identical. That means that proc equality is checked on a syntax level, not on proc result.
Lets take https://gist.github.com/4611935 First sample works just fine because number of local variables are the same and the sequence of operations are the same. Assign 123 to local variable. The second sample treated as not same because operation sequence differs - you assign 123 to different variables.
But yes, proc comparison is pretty confusing and has been removed form ruby 2.0 I presume. Now procs are compared as a regular object by its id.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With