Hi –
On Fri, 2 Oct 2009, Yossef M. wrote:
On Oct 1, 8:27Â pm, Josh C. [email protected] wrote:
On Thu, Oct 1, 2009 at 6:38 PM, Ryan D. [email protected] wrote:
*) calling (almost) any bang method on a temporary value is usually a bug.
Why is that?
What’s the point of calling a bang method there? You don’t care at all
about the object you’re mutating, and it seems like a blatant case of
premature optimization.
I disagree, at least on the second point. Using transparent language
constructs that happen to be more efficient in some dimension doesn’t
mean you’re prematurely optimizing.
For example, if I do this:
obj.meth
instead of this:
obj.send(:meth)
you could say I’m prematurely optimizing. Both exist in the language;
any non-beginning Rubyist knows about both; both fly from the fingers
quite readily. So if I choose the one that’s faster, I’m “optimizing”
– but still, unless I have no choice, I’ll choose it.
Same thing with things like map and map!. Actually I don’t
automatically reach for the in-place ones (I’m just not in the habit),
but they’re fully visible and trivially usable at the language level,
so I don’t think they can be thought of as sidetracking the programmer
into doing too much too soon about too little. In other words, all
else being equal, it isn’t necessarily bad to choose one idiom over
another in a high level language on the grounds that the one you’re
choosing is likely to shave a few cycles. If you forbid yourselves the
slightly faster ones simply because they are slightly faster, that way
lies having to test everything you write to make sure it ISN’T
performing as well as it could, so that you can’t be accused of having
prematurely optimized
What might be bad is if you get a hunch, based on no evidence, that it
would be efficient to divide every array into four subarrays before
doing a mapping, and then recombining them, and go around changing
your code so that every array is handled that way… That, I think,
is the kind of thing where you’re looking for trouble before you know
it’s there.
Of course, a certain amount of how this plays out in Ruby has to do
with Ruby being a high-level language. We can make a certain number of
choices like map vs. map! trivially, even though if we were
implementing the methods themselves, we’d be faced with a whole new
round of optimization issues and a much more fine-grained code
texture.
I tend to agree too with the interpretations of the Hoare statement
that suggest that not all optimization during development is
“premature”. It depends on what you’re writing, and on how hard it is
likely to be to go back and deal with optimizations and bottlenecks
later. I think Ryan has said “Performance isn’t an issue until it’s an
issue”, which I agree with, but I’d add that it’s not necessarily
amiss to get into some habits that cost you nothing in developer time,
do not derail you from your basic workflow, but do buy you a bit of
efficiency here and there.
Now, consider the specific cases where the bang method doesn’t return
the same value as the non-bang (viz. uniq!).
Of course you wouldn’t want to risk calling a wrong method on nil, but
that’s not an argument against using map! or sort! Just remember to
read the documentation carefully. After all, ! means “dangerous” so
You Have Been Warned
David
P.S. I’ve found this article very interesting on this score: