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.