简体   繁体   中英

Should multiple array/hash lookups be stored in a variable

I've been using Reek lately to refactor my code and one of the smells, DuplicateMethodCall , is being called on array and hash lookups, such as array[1] or hash[:key] when called multiple times.

So I was wondering if multiple array or hash lookups are so expensive, that we should be storing them in a variable rather than calling them directly, which is what everyone does from my experience.

I would not hesitate to store multiple object method calls (especially if it's a DB call) in a variable, but doing that for array and hash lookups feel like an overkill.

For example, I'll get a warning for this piece of code:

  def sort_params
    return [] if params[:reference_letter_section].nil?

    params[:reference_letter_section].map.with_index(1) do |id, index|
      { id: id, position: index }
    end
  end

but I feel like storing params[:reference_letter_section] in its own variable is too much

So I was wondering if multiple array or hash lookups are so expensive

Expensive calls are not the only reason for not doing the call multiple times. It also clutters the code without real need. Consider this not-so-contrived example:

Order.new(
  name:       params[:order][:name],
  total:      params[:order][:total],
  line_items: [
    {
      product_name: params[:order][:line_item][:product],
      price:        params[:order][:line_item][:price],
    }
  ]
)

Even though those hash accesses are super-cheap, it still makes sense to extract them, for readability reasons.

order_params     = params[:order]
line_item_params = order_params[:line_item]

Order.new(
  name:       order_params[:name],
  total:      order_params[:total],
  line_items: [
    {
      product_name: line_item_params[:product],
      price:        line_item_params[:price],
    }
  ]
)

The duplicate hash lookup represents coupling between those two lines of code. This can increase the time taken to understand the code, and can be a source of friction when changing it. Of course, within a small method like this the cost is relatively low; but if the two lines of code were further apart -- in different classes, for example -- the effects of the coupling would be much more costly.

Here's a version of your method that doesn't have the duplication:

def sort_params
  reference_letters = params[:reference_letter_section] || []
  reference_letters.map.with_index(1) do |id, index|
    { id: id, position: index }
  end
end

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM