Ruby 2.7 adds Integer#[] to support range values


There are times, when we deal with binary data and perform bitwise operations like Left Shift, Right Shift, AND etc.

For Example:

# Initializing n with 0b01001101 (binary value of 77)
> n = 0b01001101
#=> 77

# Doing bitwise Right Shift by 2 bits 
# i.e. shifting 2 bits in right direction
# 0b01001101 >> 2 will become 0b010011 (binary value of 19)
> c = (n >> 2)
#=> 19

# Performing bitwise AND operation
# Bitise AND of 0 & 1 is 0, 
# 1 & 0 is 0, 0 & 0 is 0 and 1 & 1 is 1
> c = c & 0b1111
#=> 3

In summary, to achieve above result we need to write expression as follows:

> (n >> 2) & 0b1111
#=> 3

To simplify these kind of expressions, Ruby 2.7 has extended Integer#[] to support range arguments. We can pass range (beg..end) as argument to integer i.e. selecting bits starting position from beg till end.

After Ruby 2.7

# Binary value of 77
> 0b01001101
#=> 77
# Binary value of 3
> 0b0011
#=> 3
# Passing range (2..5) as argument 
# selecting bits starting from position 2 which is 1 till position 5 which is 0
# our value will become 0b0011
> 0b01001101[2..5]
#=> 3
> 0b01001101[2...6] == 0b0011
#=> true
> 0b01001101[2, 4] == 0b0011
#=> true

Now let’s take the above expression (n >> 2) && 0b1111. This is returning 4 bits starting from position 2. Position 2 is because of 2 bits right shift and length 4 is because of AND operation with 0b1111. Thus with Ruby 2.7, we can write this expression like this:

> n[2..5]
#=> 3
> n[2...6]
#=> 3
> n[2, 4]
#=> 3

This expression looks much cleaner and readable.

There is one edge case when using this. If end is less than beg in the range (beg..end) then it’ll be handled as (beg..Float::INFINITY)

> n = 0b01001101
> n[1..0]
#=> 38
> n[1..-1]
#=> 38
> 15[-3..-4]
#=> 120