From: pcs3@... Date: 2001-11-07T14:22:52+09:00 Subject: [ruby-talk:24482] Re: "yield called out of block" David Alan Black wrote: > But I don't think eachOver57 would be likely to be an iterator. I > think it would be likely to *call* an iterator: > > class Array > def eachOver57 > find_all do |e| e > 57 end > end > end > > list = [12,34,56,78,90] > nums = list.eachOver57 # => [78,90] > > So yes, what gets returned is a stored array, but creating that array > involves iterating over another array (in this case, with find_all). eachOver57 was a trivial example, but isn't there a defacto convention that each methods are iterators? Maybe allOver57 would be a better name for a method which couldn't be used as an iterator as well. > I'm still not getting it. "yield" means "yield control to a > block/proc". You seem to be talking about a kind of built-in default > accumulator, which may or may not be useful (not sure yet :-) but > which doesn't seem to me to involve yielding. Well, yield would still yield control to a block, just not one supplied by the user, and one which must have additional information passed-in by yield if it is to impose structure (which increasingly seems to me like more trouble than its worth). In addition, yield would return whatever the block returned (on the block's final call). > For instance: when you say "have an iterator method (which doesn't > have to return anything else) return a call to yield", what I would > want to know is: to what is that yield call yielding control? And if > nothing -- if this new "yield" isn't yielding -- , then why is it > called "yield"? yield would detect that it had been called without being given any block, and would then (instead of causing an error) yield control to a default accumulator block (but in this case yield would need to pass-in an additional argument-- the number of args yield was called with, so structure can be imposed by the block, which would need to have some state information in-between calls, not least of all the Array it's building up). Every call to yield in this case would return whatever the block returned on it's final call. > (By the way, I'm not as happy as you are about dismissing return > values of iterators, but we can leave that to the side :-) This wouldn't have to interfere with the return values of iterators at all if you didn't want to (for the same reason it wouldn't work in all cases). If a block is supplied and the iterator method is used normally, then there would be no change in behavior, because yield wouldn't be yielding control to the default block and passing in additional information to this block, which could be thought of as an accumulator, and the return value of yield wouldn't be modified. If you want to return something else in the iterator method that's fine as well (in fact, if you only wanted the iterator method for some other return value, then this would save you from passing-in a do-nothing block). I'm almost tempted to write a proof-of-concept demonstrator. But anything I could write would have some limitations-- namely, that it would only work on its first use. Because each time the block is called it accumulates state information, so how would it know either that it had left its calling context, or entered a new one so clear all the state information and start over? Let me try to illustrate what I mean: def someIterator altyield 1 #where altyield is whatever I could implement end nums = someIterator #nums is now [1] nums = someIterator #nums is now [1, 1] From this you can see though, that someIterator only returns the list because altyield was the last thing to return something (and hence is the return value of the method). As it currently stands yield just returns nil. Had you returned something after altyield, nums would be whatever that is, and the same after both calls. But of course, this is all I could implement, because altyield would just be a method, so how would I get a handle to whatever block was passed into someIterator? Any demonstrator I could write would have to accept a named block if one was supplied (or nil to indicate that no block is supplied, so use the default accumulator block).