On Thu, Mar 27, 2003 at 01:01:25AM +0900, Mauricio FernŠŌdez wrote:
> For the record:
> 
> There's one thing Ruby's closures do and Python's cannot, as described in
> [ruby-talk:67618]. Doesn't seem to make a difference in praxis and there
> is a workaround to solve that, though.

This isn't entirely true.  I can write the following ruby code:

   make_counter = proc { |start|
     proc { |inc| start += inc }
   }

   counter = make_counter[0]
   p counter[3]  # ==> 3
   p counter[2]  # ==> 5

and the following Python code would be equivalent:

  def make_counter(start):
    l = lambda inc, v=vars(): (
      v.update({'start' : v['start'] + inc}), v['start'])[1]
    return l

  counter = make_counter(0)
  print counter(3)
  print counter(2)

I really don't know Python very well, so there's probably a much better
way to write this.  The idea, though is that all local vars are stored
in a dict; that dict is accessible using the vars() function.  I can
store that dict for use later (and thus retain access to all the local
variables, as in a real closure) by using default arguments to the lambda.

Note that I used v.update() instead of v[]= because in Python, a=b is a
statement, and lambdas in Python only work with expressions.  Ruby
doesn't make a significant distinction between expressions and
statements, so there is a big difference between what is allowed in a
lambda in Python and what is allowed in a lambda in Ruby.

Another big difference is that lambdas in Python can take only one
expression.  To get around that limitation, I had to use a tuple (I
found this trick on http://p-nand-q.com/lambda.htm).  Ruby's lambdas
allow multiple expressions to be chained together with carriage returns
or semicolons, and thus do not have this problem.

In Python's defense, Python lambdas are callable the same way that
functions are called.  Ruby requires special syntax (either f[] or
f.call()) to call a lambda.  This is only a minor nuisance in practice,
since it's always possible to create a Method object that is callable
the same way that a lambda is called.

Paul