Given this code:
class Foo
def length
0
end
end
Foo.new.length > 0
rubocop reports:
`foo.rb:7:4: C: Style/ZeroLengthPredicate: Use !empty? instead of length > 0.
but making that change will result in:
undefined method `empty?' for #<Foo:0x007ff3db079f78> (NoMethodError)
This is a valid assumption to make in the majority of cases. Can you provide a real-world example of a commonly used Ruby library which implements #length but not #empty??
@alexdowad I agree it will work in the majority of cases, but it is not correct for _all_ cases. For example,if I make an object representing a Vehicle and length represents it's length in meters. I may need to say "If the car is greater than 3m, then driver must have a commercial license". There's lots of usages of length or size that are not "discrete number of parts".
In that case RC will produce a false positive. The question is, are false positives common enough and serious enough to make this cop more harmful than helpful?
...Actually, I should have said: RC will not generate a false positive in the hypothetical situation you mention. Because this cop looks only for .length == 0, not .length > 3.
This was a calculated risk. I should always encourage people to add empty? predicates. If people see this as a big problem, they should just disable the check.
It just happened to me on Mysql2::Result (it doesn't implement empty?)
It's quite popular rubygem.
This happened to me with Rails 3.2 --
A controller checked params[:file].size == 0, which worked fine before, but got autocorrected to params[:file].empty?, which throws
undefined method 'empty?' for #<ActionDispatch::Http::UploadedFile:0x4e5e22e1>
This can lead to some problems when making SketchUp extensions. In the SketchUp Ruby API a Vector3d has a length method returning a Length object (a physical length). There is however no Vector3d.empty? method, as a zero length vector isn't refereed to as "empty".
@alexdowad I just ran into a real-world example of a commonly used Ruby library which only implements #size and not #length or #empty.
Sidekiq::ProcessSet.new.size > 0 gets changed to !Sidekiq::ProcessSet.new.empty? and throws an error.
Worth mentioning I just hit this issue- ideally you should be able to trust rubocop auto-corrects, but you can't for this one!
I'll add one more example, Restforce::Collection.
In our case, we'll disable autocorrect for this cop but leave the rule enabled, so that we know about it and we can add an inline exception to the rule if needed.
While I do agree that using #empty? is a good suggestion, this is the first cop that breaks the expectation that I can trust RuboCop's autocorrect. Maybe it was a wrong assumption to begin with, but I haven't had problems with other cops.
Most helpful comment
@alexdowad I just ran into a real-world example of a commonly used Ruby library which only implements #size and not #length or #empty.
Sidekiq::ProcessSet.new.size > 0gets changed to!Sidekiq::ProcessSet.new.empty?and throws an error.