From: raja@... (Raja S.) Date: 2000-12-09T18:10:06+09:00 Subject: [ruby-talk:6958] bounds checking in arrays I've been out of town this past week and am catching up on my earlier discussion on the non-existence of bounds checking in Array#[] and Array#[]=. I'd like to discuss a few thoughts I've had on Ruby in the intervening time. * Leaving the issue of the design rationale of the non-bounds checking of #[] for the moment, I was curious to see how this could be emulated in Ruby. Redefining Array#[] and Array[]= was raised earlier as an option with the caveat that it could possibly break existing code. Another alternative seem that we could sub-class off of Array: --------------------------------------------------------------------------- class Vector < Array def Vector.[] (*args) super end def initialize (*args) super (args.length) # create an empty array for i in (0...self.length) # and populate it self[i]=args[i] end end def [] (*args) validateIndex (args) super end def []= (*args) validateIndex (args[0...-1]) super end end --------------------------------------------------------------------------- The intention is to use it as: v1 = Vector.new(2,3,5,7,11) v2 = Vector['alpha', 'beta', 'gamma'] One could get all the built-in methods of arrays in Vectors + bounds checking without potentially breaking pre-existing code. The only loss, as far as I can see, is the inability to express literal 'vectors'. Of course if we had Array#fetch we could just alias #[] to #fetch in Vector. In that context, since Matz brought up the discussion of a possible alternative name for Array#fetch, my preference would be to keep it in sync with that of Hash#fetch. Having said that my real prefernce would be for #at (concise; Smalltalk, Eiffel) though #get (also relatively concise; Java) Raja --------------------------------------------------------------------------- p.s. Question: being latently typed I presume "method overloading" doesn't fit in the Ruby framework (as it doesn't in Python nor CLOS). As a result of which #validateindex needs to do its own type-checking leading to the rather verbose and messy: def validateIndex (args) case args.length when 1 idx = args[0] case idx when Float, Fixnum unless ((0 ... self.length) === idx) raise IndexError, "index out of range [0...#{self.length}]: #{idx}" end when Range r=args[0] # just check to see if the range starts in the Vector # truncate if it goes beyond unless (0...self.length) === r.min raise IndexError, "index out of range [0...#{self.length}]: #{r}" end else raise IndexError, "Invalid index: #{idx.inspect}" end when 2 start=args[0] # just check to see if the segment starts in the Vector # truncate if it goes beyond unless (0...self.length) === start raise IndexError, "index out of range [0...#{self.length}]: " "[#{start},#{len}]" end else raise IndexError, "Invalid index: #{args.inspect}" end end Can this be expressed better?