From: Joel VanderWerf Date: 2001-09-02T12:10:56+09:00 Subject: [ruby-talk:20687] Re: Iterating by links David Alan Black wrote: > What I'm finding is that it's hard to automate because there are > different things that could cause the exception. For instance, in David, Semantic issues aside, the implementation using exceptions is problematic. One possible fix: in the "rescue NameError" clause, compare the exception's backtrace depth with the current stack depth (i.e., caller.size). Apparently, these differ by 4 if and only if the exception was generated within the loop, so we can re-raise just those exceptions caused by user code. However, using a constant in this way makes me itch, so I considered going back to the respond_to? approach, which is at worst about 20% slower than using exceptions to test implicitly. But then there are the semantic questions: What terminates the enumeration? A nil return value from send? An object that doesn't respond to the message? Either? And are terminating objects included in the enumeration? My current feeling (I've changed 180 degrees on this) is that an object that doesn't respond is actually an error condition, not a termination condition. This means that my tree example simply won't work as is (but see below). There are programming errors that will be ignored unless we do it this way. (Perhaps you have several classes of objects, and you forgot to define a 'next' attribute for one of them, or you simply linked the wrong object into your list.) Also, nil (or false) terminates the enumeration without being included in it, which is the classic linked list semantics. Here are two ways to iterate over a tree branch: tree = [[0, [1, 2]], 3, [4, 5, [6, 7, 8]], 9] at_random = proc { |x| x.kind_of?(Array) && x.at(rand(x.size)) } for node in tree.by at_random p node end class Object def at_random nil end end class Array def at_random at(rand(size)) end end for node in tree.by :at_random p node end The latter is more elegant and probably more efficient, but the former is nice if you just want to do it on the fly. I'll release the updated version on the web, along with some other enumerable stuff, later this weekend. BTW, is there some reason why LinkedListDelegator shouldn't be hidden away inside Enumerable's namespace, rather than in the global namespace? Thanks for your helpful comments! Joel