Reopening with a bang: cannot assign to self

D

David Brady

Hello,

I'm writing some code that benefits from extending Array. One of the
methods wants to be a bang method. How do I reassign the contents of an
Array from within it? (I recognize that subclassing Array might be more
proper, but I think the problem exists in the subclass as well.)

class Array
# returns copy of array, with each value divided by the sum of
# the array elements. e.g. [1,2,2] => [0.2, 0.4, 0.4].
# (this code works fine)
def normalize
total = Float( self.inject {|x,y| x+y} )
self.collect {|x| x/total}
end

# returns modified array unless array.sum == 1.0, in which case
# array is not modified and method returns nil
# (this code does not work: syntax error - cannot assign to self)
def normalize!
total = Float( self.inject {|x,y| x+y} )
if total.zero?
nil
else
self = self.collect {|x| x/total}
end
end
end

I can work around the problem by iterating and using self.[]= but the
collect is so much cleaner, I have to wonder if there's not a way to use it.

Hrm, I've just found "Array#collect!", which will do the trick I need,
but I still wonder what the proper Ruby idiom is for extending a class
with a bang method that essentially modifies or replaces the entire
contents of the object, when there isn't an accessor method. For
example, how would you do "Fixnum#div!(x)", e.g. the equivalend of f /= x?

I recognize that this entire line of reasoning may be the result of
wrongheaded thinking about Ruby. If so, please enlighten me.

-dB
 
D

David Brady

Daniel said:
Is Array#replace what you're looking for?

Possibly. Array#replace seems to be like collect!, it's a nicer way
around the specific problem for Array only. Well, *some* classes only.
Hash, String and Array all seem to have #replace. But Fixnum, Bignum,
Float, and File (to name the few I just tested right now) do not.

I'm asking to see if there's a general way to do it in any class.

Actually, replace is an even better example of my question. How would
you implement #replace in an arbitrary class that didn't already support
it, such as Float or StringIO?

-dB
 
D

Daniel Amelang

I see. Well, there isn't a general way to do it in any class, since
some classes (like Fixnum) are immutable.

For most classes, though, there will be a way to do what you want by
finding a 'replace'-like method.

Dan
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,967
Messages
2,570,148
Members
46,694
Latest member
LetaCadwal

Latest Threads

Top