On 10/7/05, Daniel Amelang <daniel.amelang / gmail.com> wrote: > I wonder how many people *do* fully understand the whole block/proc/ > lambda/Proc.new/Method/UnboundMethod/etc relationships and the use of > next/break/redo/return/etc within each of them (not to mention the > different styles/rules when it comes to parameter lists). > > (no, I'm not looking for a comprehensize explanation, just pointing > out the complexity of the situation) > > Often, when a simplification is proposed, it is struck down as 'just a > way to make it easier for newbies that are still learning the > language' (ironically, David is oft to say such) and not really a good > idea. > > After 3 years of Ruby programming, I'm still left scratching my head > at times. Maybe I'm just a little slow. No, I don't think it's just you. I don't think that your assessment of David's past comments is fair or accurate. It certainly doesn't match my recollection of what David has said about the attempts to simplify block/etc. I *believe* that what I'm about to say is similar to what David has said, but it's obviously my interpretation and as such is not to be taken as "speaking for David". The problem that I see is that most attempts to "clean up" the block/ proc divide rely on some pretty ugly syntax and have, at least to my eye, relied more on a theoretical unification than the practical use. Some attempts have also attempted to eliminate Ruby's pragmatic one-block case and yield. That is fix is needed may not be in question; the nature of the fixes provided so far, however, seem to add to the confusion. Blocks and Procs are mostly interchangeable. There are some differences in the way that parameters are handled (block parameters are assigned as parallel variables; Proc parameters are assigned as function parameters) and the way that they respond to break and return. There might be other differences, but these are the major ones. I would argue that the distinction between the two should be in the *use*, not in the definition. Specifically: def test_yield yield 1 end def test_call(&p) p.call(1) end z = lambda { |x, y| [ x, y ] } test_yield { |x, y| [ x, y ] } # => [ 1, nil ] test_yield &z # => [ 1, nil ] test_call { |x, y| [ x, y ] } # => [ 1, nil ] test_call &z # => ArgumentError To me, the surprising result (I know, I know) is *not* the second test_yield, but rather the first test_call (mostly because a "puts p.arity" indicates that the arity is 2 in both cases). In the case of yield, I don't mind that it's treated as (almost): def yield(*args, &block) &block.call(*args) end ...but for #call, I would want arity respected, whether it's a simple block or a full lambda. To make this cleaner, it might be better to have a second method, say #yield (problematic because yield is a keyword, but something like that) that allows for either style to be called as a method on the Proc. I don't have an answer for the other problem (break, return, etc.). -austin -- Austin Ziegler * halostatue / gmail.com * Alternate: austin / halostatue.ca