From: Robert Klemme Date: 2008-02-23T07:27:17+09:00 Subject: Re: ||= [] idiom 2008/2/22, MenTaLguY : > On Fri, 22 Feb 2008 21:33:22 +0900, Thufir wrote: > >> Often it can make sense to factor the ||= portion into a separate > >> method: > >> > >> def category_for(tag) > >> @categories[tag] ||= [] > >> end > >> > >> # ... > >> > >> category_for(resource.tag) << resource > > > > > What's the real-world application of this? > > > There are two reasons to do it: > > 1. If you're doing this in non-trivial code, you're likely to end up > with multiple @categories[something] ||= [] scattered around; it > only makes sense to factor them into a single method at that point. > This is an advantage for maintainability. > > 2. "category_for" has a more direct meaning in the problem domain: > category_for(tag) will simply give you the category array for a > particular tag, without needing to expose on the spot the details > of how that category array is obtained. This is an advantage for > readability. > > Also, regarding maintainability again, let's say that you decide to > start using objects of class Category instead of arrays; assuming > there is a Category#<< for adding a resource to a category, you can > simply change this: > > > def category_for(tag) > @categories[tag] ||= [] > end > > > to this: > > def category_for(tag) > @categories[tag] ||= Category.new > end > > It's the DRY principle: Don't Repeat Yourself. > > If there is repetition in your code, it is harder to read (because > you have to mentally filter out the repeated parts to see the > differences -- which are the important part), and you make more work > for yourself (because you must then edit many different places to > effect a single change, and are more likely to make mistakes). But all these points you mention do also apply to the Hash based approach. You can even use the same wording, if you like: @category_for = Hash.new {|h, tag| h[tag] = []} I was expecting reasoning that would highlight advantages of using a method here. The only thing that comes to mind is that if you want to exchange the implementation altogether, then a method based approach is better. But in that case you'd probably do def add_to_category(tag, item) (@cat[tag] ||= []) << item end Because that abstracts away category creation *and* adding to the structure. On the flipside, for small scripts that Hash based approach has the advantage of being shorter (because no method is needed). Kind regards robert -- use.inject do |as, often| as.you_can - without end