From: Yukihiro Matsumoto Date: 2007-10-31T09:17:01+09:00 Subject: Re: new Enumerable.butfirst method Hi, In message "Re: new Enumerable.butfirst method" on Wed, 31 Oct 2007 03:10:25 +0900, David Flanagan writes: |> It's a traditional name (but slightly different behavior) inherited |> from Logo. In Logo, butfirst is cdr in Lisp, which returns given list |> with its first element removed. | |Well tradition helps, but I think I'd still prefer another name. I abandoned #butfirst this time (just reverted). Maybe after I introduce LazyArray in Ruby 2.0. |Some enumerable methods return arrays, some return enumerators, and it |is beginning to get confusing. I made a little table of the methods I'm |discussing here: | |Method block with block without block |------------------------------------------------------------------- |butfirst iterates returns collection returns enumerator |first not allowed not allowed returns array |take selects returns array returns array |drop selects returns array returns array |grep iterates returns array returns array |select selects returns array returns enumerator |find selects returns element returns enumerator I just changed with-block form of #take and #drop to #take_while and #drop_while respectively. After those change figure becomes Method block with block without block ------------------------------------------------------------------- first not allowed not allowed returns array take not allowed not allowed returns array drop not allowed not allowed returns array take_while selects returns array not allowed drop_while selects returns array not allowed grep iterates returns array returns array select selects returns array returns enumerator find selects returns element returns enumerator so that inconsistency reduced much (with exception of #grep). |I have a couple of related thoughts about this. | |First, are you sure that you want methods like find and select to return |enumerators when called without a block? Since the block is used for |filtering elements rather than enumerating them, I don't really see the |use case here. I think I'd prefer methods like these to require a |block. If someone really wants to create an enumerator from them, they |can use enum_for, of course. I'd suggest that only more traditional |iterators should return enumerators when called without a block. I think ary.find.with_index{|x,i|...} for example, to be useful sometimes. |Second, I wonder if it is possible to unify Array and Enumerator so that |one behaves like the other. Then we could treat all methods as if they |returned an array or an enumerator. If we add next and rewind methods |to Array (which I think would be easy) then we can treat the return |value of take, drop, select, reject, etc. as an enumerator. | |But an even nicer thing would be if Enumerators could act like lazily |filled arrays. That is, if I have an enumerator e, but use it like an |array, it calls to_a on itself internally and then dispatches to the |array. With that change, you could modify Enumerable#grep, for example, |so that it returns an enumerator instead of an array. If you never treat |the result as an array, to_a never gets called, and you get pipe-like |behavior that works with unbounded collections. That's what I called LazyArray above. That's the important issue for Ruby 2.0 (i.e. not for this Christmas). matz.