I kinda feel like I'm being called out as I'm on record (many times) for 2/3rds of your examples so I'll address them specifically:
"Don't concatenate strings, use string interpolation instead"
Using a recent real example from this list where I suggested interpolation:
m.ClassMethodString + " " + m.ClassMethodString + ": " + m.ClassMethodInteger.to_s
mmmmm java code.
1) slower -- several more method calls
2) wasteful -- creates much more garbage
3) longer/uglier -- I'd argue that it is much less elegant
vs
"#{m.ClassMethodString} #{m.ClassMethodString}: #{m.ClassMethodInteger}"
1) clarity -- it's just a string.
2) elegance -- it's JUST a string AND you don't need those stupid #to_s calls.
3) efficient -- takes less time, uses less memory, makes less garbage, and even easier to read.
"Don't use Enumerable#inject to build up objects" etc. etc.
Given #inject's other alias, #reduce, it is obvious that you don't use #inject for building up other objects. Even in a functional style of programming you'd _never_ see it building up anything. You'd see it REDUCING (folding) an object. If #inject is applied in a non-folding manner, it isn't functional, it is just dumb. Don't pretend otherwise (and if you do pretend otherwise, go read more books on lisp--start with SICP). The second I see a semicolon (or return) in an inject, I immediately suspect that someone is writing clevar/stupid code.
I don't have any recent examples from the list, but I'm on record in multiple mediums ranting against people who use #inject improperly. I'll make up one based on examples I've seen time and time again:
return im_a_lazy_bastard.inject(Hash.new 0) { |h, o| h[o.really_really_lazy] += 1; h }
vs
counter = Hash.new 0
thingies.each do |o|
counter[o.key] += 1
end
return counter
1) I use #each because it adds CLARITY. I want to enumerate each element. I'm not folding anything.
2) Yes, it's faster. I don't actually care about that nearly as much as #1.
3) Yes, it is more lines:
1) but only if you write the inject version that way.
2) I use the Weirich Method [1][2] of choosing {} vs do/end. INCREASING clarity and intent.
3) each line is a stand-alone concept that helps increase clarity.
Here is a perfect example of an actual folding application of #inject:
classname.split(/::/).inject(Object) { |k, n| k.const_get n }
vs:
k = Object
classname.split(/::/).each { |n| k = k.const_get n }
k
As you can see, the #inject version is incredibly clear and concise. The second example takes longer to figure out. That is what the natural fit of a well designed method is supposed to do.
···
On Jun 20, 2012, at 07:43 , Jan E. wrote:
---
Come to think of it (!!!) I DO have a real world example of inject that I used in my Ruby Sadism talk:
if MODELS.keys.inject(true) {|b, klass| b and klass.constantize.columns.map(&:name).include? association.options[:foreign_key]} then
# ...
end
Have fun with that... It's probably the most egregious use of inject I've ever found. The original author actually argued that he wrote it that way "for maintainability".
[1]: http://onestepback.org/index.cgi/Tech/Ruby/BraceVsDoEnd.rdoc
[2]: http://talklikeaduck.denhaven2.com/2007/10/02/ruby-blocks-do-or-brace