Difference between '..' (double-dot) and '...' (triple-dot) in range generation?

juil picture juil · Mar 13, 2012 · Viewed 50k times · Source

I've just started learning Ruby and Ruby on Rails and came across validation code that uses ranges:

validates_inclusion_of :age, :in => 21..99
validates_exclusion_of :age, :in => 0...21, :message => "Sorry, you must be over 21"

At first I thought the difference was in the inclusion of endpoints, but in the API docs I looked into, it didn't seem to matter whether it was .. or ...: it always included the endpoints.

However, I did some testing in irb and it seemed to indicate that .. includes both endpoints, while ... only included the lower bound but not the upper one. Is this correct?

Answer

Andrew Marshall picture Andrew Marshall · Mar 13, 2012

The documentation for Range says this:

Ranges constructed using .. run from the beginning to the end inclusively. Those created using ... exclude the end value.

So a..b is like a <= x <= b, whereas a...b is like a <= x < b.


Note that, while to_a on a Range of integers gives a collection of integers, a Range is not a set of values, but simply a pair of start/end values:

(1..5).include?(5)           #=> true
(1...5).include?(5)          #=> false

(1..4).include?(4.1)         #=> false
(1...5).include?(4.1)        #=> true
(1..4).to_a == (1...5).to_a  #=> true
(1..4) == (1...5)            #=> false


The docs used to not include this, instead requiring reading the Pickaxe’s section on Ranges. Thanks to @MarkAmery (see below) for noting this update.