Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use `next` with an accumulator argument in a `reduce`

There is a cop: RuboCop::Cop::Lint::NextWithoutAccumulator.

Is anyone able to explain what this cop is for, how is it supposed to improve the code in in what way?

Does it improve readability, efficiency?

github code.

like image 340
Andrey Deineko Avatar asked Dec 28 '25 00:12

Andrey Deineko


2 Answers

Lets consider sample code from the documentation:

# bad
result = (1..4).reduce(0) do |acc, i|
  next if i.odd?
  acc + i
end

If you try this in the console, you will get NoMethodError exception for the nil object. This is because next "returns" nil if there is no object specified. You can treat it as return for iterators.

For reduce method it may result in some unexpected behavior as it needs some value returned by the block. If i is odd, then next is evaluated and block gives nil as the result. In the following iterator acc is equal to nil and it can't add integer to it. In our example, first iteration is for i = 1, next sets acc to nil as the result of the block.

In some cases you can get correct value for the enumerable, but in general it is safer to specify value for next inside.

like image 55
Maciej Małecki Avatar answered Dec 30 '25 14:12

Maciej Małecki


Bad

result = (1..4).reduce(0) do |acc, i|
  next if i.odd?
  acc + i
end

Good

result = (1..4).reduce(0) do |acc, i|
  next acc if i.odd?
  acc + i
end

As @smefju pointed out, next by itself implicitly returns nil and will cause a NoMethodError when it is passed in as the parameter of the next execution of the block.

like image 45
Gregory Ray Avatar answered Dec 30 '25 14:12

Gregory Ray