On Sun, 2003-03-23 at 16:17, Paul Prescod wrote: Paul, Again ... good comments. I have just a few comments on your blocks section. > On Blocks > > You say that Python has generators which are equivalent to Ruby's > blocks. I think that blocks and generators are mostly unrelated. [...] Yes and no. Although they are entirely different things, they both are used for do "iteration-like" stuff in their respective languages. That and the fact they both use the keyword "yield" (although with complete different semantics!) leads people to confuse the two. Ruby Blocks are nothing more than a little syntactical sugar for anonyous functions/closures. The Ruby yield is nothing more than a function call to a special anonymous function attached to a method. A Python generator is really a form of coroutine. The Python yield statement doesn't follow function call/return semantics at all, but allows the generator to switch between the main code and the generator code in coroutine style. > But generators do allow you to do something that is very difficult > without them. Consider this code: > > http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/66316 Actually, this code is easy to duplicate with blocks ... def fib x = 0 y = 1 proc { x, y = y, x + y x } end g = fib 9.times { print g.call, " " } puts This problem is was easy to convert because the basic loop is easy to unroll. If the algorithm were more deeply nested, or used yield in multiple locations, the conversion would be more obscure. For example, a generator that returned the leaves of a tree data structure would be fairly easy using generators, but more difficult without. For those tougher problems, a Ruby programmer might resort to using continuations. Continuations are much more powerful than generators, but also much harder to use and understand. So, in summary, this is how I see it. Ruby uses blocks/closures for most of its iteration needs, switching to continuations or other mechanisms for the hard cases. Python uses a more powerful technique that handles the common case and some of the harder cases. One more minor thing ... > [...] but you can only pass one block (unless you wrap it in a > function!). I think. No, you would simply pass a proc object instead ... def upload(handle_data_proc, output_proc, print_error_proc, etc) ... upload(proc{|data| blocks.append(data)}, proc{|data| logger.write_msg(data)}, proc{ logger.write_err(data)}, 5) -- -- Jim Weirich jweirich / one.net http://w3.one.net/~jweirich --------------------------------------------------------------------- "Beware of bugs in the above code; I have only proved it correct, not tried it." -- Donald Knuth (in a memo to Peter van Emde Boas)