tags:

views:

46

answers:

1

This has been driving me nuts, I'm posting here after a lot of looking around.

I'd like to know if two variables pointing to the same Proc are the pointing to the same Proc. I'm sure it must be something I'm not getting so for example why do all of these return false?

class LambdaFunctions
  def self.LambdaFunction1
    lambda { |t| t ** 2}
  end
end

a = LambdaFunctions.LambdaFunction1
b = LambdaFunctions.LambdaFunction1

puts LambdaFunctions.LambdaFunction1
puts a
puts b

puts a == b
puts a === b
puts a.eql?(b)
puts a.equal?(b)
puts a == LambdaFunctions.LambdaFunction1
puts a === LambdaFunctions.LambdaFunction1
puts a.eql?(LambdaFunctions.LambdaFunction1)
puts a.equal?(LambdaFunctions.LambdaFunction1)

Thank you Mark, you made it a lot clearer. In previous it was returning new objects each time so the equal? function was never going to return true. The two lambdas were functionally the same but not the same object. So if you create one version and then return it back in the method you can test it's identity. The following makes more sense and works as I intended.

class LambdaFunctions

  @lambda1 = lambda { |t| t ** 2}
  @lambda2 = lambda { |t| t ** 2}

  def self.LambdaFunction1
    @lambda1
  end

  def self.LambdaFunction2
    @lambda2
  end
end

func1 = LambdaFunctions.LambdaFunction1
func2 = LambdaFunctions.LambdaFunction1
func3 = LambdaFunctions.LambdaFunction2

puts func1.equal?(func2) # true
puts func1.equal?(func3) # false
puts func1.equal?(LambdaFunctions.LambdaFunction1) # true
puts func3.equal?(LambdaFunctions.LambdaFunction1) # false
puts func3.equal?(LambdaFunctions.LambdaFunction2) # true
+3  A: 

While the lambda is effectively equivalent, each call to LambdaFunctions.LambdaFunction1 returns a new instance of the lambda. It would make sense for procs to be equivalent only by identity, not by value, since it would be virtually impossible to determine programmatic equivalence.

What I mean is, if procs could be determined to be equivalent based on what they did, then lambda { 3 } and lambda { 1 + 2 } would be equivalent. With lambdas any more complicated than that, to determine equivalence would basically require a solution to the halting problem.

To determine equivalent identity (per the comment), refer to Object#equal?:

Unlike ==, the equal? method should never be overridden by subclasses: it is used to determine object identity (that is, a.equal?(b) iff a is the same object as b).

If you really need a and b to be the same object, then you need to return the same lambda every time; this means you need to assign the lambda to an instance variable in the LambdaFunctions class, for instance, and return that.

ruby-1.9.1-p378 > class LambdaFunctions
ruby-1.9.1-p378 ?>   @func1 = lambda { |t| t ** 2 }
ruby-1.9.1-p378 ?>   def self.LambdaFunction1
ruby-1.9.1-p378 ?>      @func1
ruby-1.9.1-p378 ?>    end
ruby-1.9.1-p378 ?>  end
 => nil 
ruby-1.9.1-p378 > a = LambdaFunctions.LambdaFunction1
 => #<Proc:0x0000010099e370@(irb):10 (lambda)> 
ruby-1.9.1-p378 > b = LambdaFunctions.LambdaFunction1 # same address as a
 => #<Proc:0x0000010099e370@(irb):10 (lambda)> 
ruby-1.9.1-p378 > a == b
 => true 
Mark Rushakoff
I thought it might be something like that. I suppose the next question I have is how do you test by identity then?
Craig Norton
I just wrote the example and returned to see you'd written an example for me. Thank you very much, it is quite obvious now it's pointed out.
Craig Norton
Actually, in the general case, it's not just virtually impossible to determine programmatic equivalence, it just *is* impossible. Period. Proof: if programmatic equivalence were decidable, I could solve the Halting Problem like this: `def halts?(proc); proc == lambda { while true; end } end`.
Jörg W Mittag