From: Florian Gross Date: 2004-10-05T09:39:52+09:00 Subject: Re: [RCR] New [] Semantics --------------070407000500050706060101 Content-Type: text/plain; charset=us-ascii; format=flowed Content-Transfer-Encoding: 7bit Bill Atkins wrote: > Currently, the following code > > a = [1, 2, 3, 4, 5] > a[0, 3] > > returns > > [1, 2, 3] > > This is somewhat counter-intuitive. Since Ruby has a built-in range > type, [] ought to take advantage of it. I propose that the [] > operators be redefined so that this behavior can only be achieved by > explicitly providing a Range, e.g. a[0...3]. The original code would > then work like #values_at and return [1, 3]. I've also thought about this circa one and a half year ago. (And I didn't even realize that I'm using Ruby for that long a time already. I still feel like I've only barely scratched the surface of what this language is able to do and there's so many unexplored libraries, concepts, mind sets that I haven't explored properly yet...) That aside, my solution was to use ary[[0, 1..3, 4]] for this. I coded up an implementation of it, but please note that this is quite old code. I didn't know about values_at at the time I wrote it and I'm not even sure if the code is correct in all cases. (Had I written this now, I would want to have a handful of test cases, even though I might hesitate to write them -- I really need to make this a habit.) I have attached the code, because it is a quick way of testing this alternate syntax from irb -- it might be especially interesting to see what happens with other Enumerables in action -- it is hard to think about such border cases without an implementation. So, what do you think about using this syntax instead? It is slightly more complex than the one you proposed of course, but it is also consistent with ary[1..3] and could in theory be useful in more cases. Regards, Florian Gross --------------070407000500050706060101 Content-Type: text/plain; name="array_fetch_array.rb" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="array_fetch_array.rb" # this changes Array#[] so that it will also take arrays # e. g.: # ary = ["foo", "bar", "qux", "quz", "quv"] # ary[[0..1, 0..2, 0..3]] # => ["foo", "bar", "foo", "bar", "qux", "foo", "bar", "qux", "quz"] # it also changes Array#[]= # e. g.: # ary = (100..110).to_a # ary[[0..3, 6..9]] = (0..3).to_a + (6..9).to_a # ary # => [0, 1, 2, 3, 104, 105, 6, 7, 8, 9, 110] class Array alias :old_get :[] def [](index, *more) if !more.empty? return old_get(index, *more) # Ranges are likely handled more efficently internally therefore we ignore them elsif index.respond_to?(:each) and !index.is_a? Range result = [] index.each { |subindex| element = self[subindex] element = [element] unless element.is_a? Array result += element } return result else return old_get(index) end end alias :old_set :[]= def []=(index, *more) args = more.clone to = more.pop old_to = to.clone raise ArgumentError unless to if !more.empty? return old_set(index, *args) # Ranges are likely handled more efficently internally therefore we ignore them elsif index.respond_to?(:each) and !index.is_a? Range index.each { |subindex| self[subindex] = to.slice!(0 ... subindex.length) } return old_to - to else return old_set(index, *args) end end end --------------070407000500050706060101--