Project

General

Profile

Feature #13495

add Range#count as an alias to Range#size

Added by AaronLasseigne (Aaron Lasseigne) over 2 years ago. Updated over 2 years ago.

Status:
Rejected
Priority:
Normal
Assignee:
-
Target version:
-
[ruby-core:80831]

Description

For infinite ranges you can't call count, you have to call size.

irb> (1..Float::INFINITY).count # have to interrupt to stop it

irb> (1..Float::INFINITY).size
=> Infinity

The problem with this is that Range is an Enumerable. Enumerable does not have size it has count. So, if you want to implement a method for any Enumerable and you want to check the number of items you can't rely on count. Instead you have to do:

enum_count =
  begin
    size
  rescue NameError
    count
  end

Making Range#count as an alias of Range#size would allow people to make methods for Enumerable classes that rely on count.

History

Updated by Hanmac (Hans Mackowiak) over 2 years ago

we can't do that.
Enumerable#count does can take a block with you can define that you want to count.

(1..4).count(&:even?) #=> 2

so we can't make Range#count be an alias for Range#size without breaking other stuff.

Updated by AaronLasseigne (Aaron Lasseigne) over 2 years ago

I should have considered that. I was focused on the use case at hand. :(

I still feel like there needs to be a way to do this that's safe. Perhaps the solution is adding Enumerable#size and letting size be the option that's safe for infinite lists.

Updated by marcandre (Marc-Andre Lafortune) over 2 years ago

  • Status changed from Open to Rejected

size calculates the size lazily, without enumerating. If it can't, it returns nil.
count calculates the size by doing the actual enumeration. It never returns nil, but may never finish.

(1..10**8).count # => takes a few seconds
(1..10**8).size # => instant

Note that some ranges don't have sizes (mostly because I was too lazy to implement it for ranges of strings):

('a1'..'zz').size # => nil 
('a1'..'zz').count # => 259 

In short: understand the difference and use whichever method is right for the task.

Updated by marcandre (Marc-Andre Lafortune) over 2 years ago

PS: "Enumerable does not have size" is incorrect. Enumerable have a size method, although it may return nil if the result can not be calculated lazily.

Updated by AaronLasseigne (Aaron Lasseigne) over 2 years ago

PS: "Enumerable does not have size" is incorrect. Enumerable have a size method, although it may return nil if the result can not be calculated lazily.

I don't think that's true. The docs don't show it and it doesn't get added when you include Enumerable.

[1] pry(main)> class Foo
[1] pry(main)*   include Enumerable
[1] pry(main)* end
=> Foo
[2] pry(main)> Foo.methods.include?(:size)
=> false
[3] pry(main)>

Aside from that, it means you can't create functions that are designed to work with Enumerable classes and depend on anything to get a proper size/length/count from them.

Updated by marcandre (Marc-Andre Lafortune) over 2 years ago

Sorry, I got confused. Enumerator has a size method, not Enumerable.

Also available in: Atom PDF