user3467349
user3467349

Reputation: 3191

What does the bracket operator do to a FixNum in Ruby?

Coming from Python I find the following behaviour very surprising:

irb(main):211:0> x= 33
=> 33
irb(main):212:0> x[0]
=> 1
irb(main):213:0> x[1]
=> 0
irb(main):214:0> x[2]
=> 0

Is there a rationale/philosophy for not raising an error in this example?

Upvotes: 2

Views: 369

Answers (4)

tadman
tadman

Reputation: 211560

You might be a little confused about what this is doing internally, but that's normal when dealing with Ruby because it's quite unlike other scripting languages. Unless you've used SmallTalk it might even seem insane.

When Ruby sees the following code:

x = 6
x[1]

What it's actually doing is this:

x.send(:[], 6) # Send :[] method call to x with arguments [ 6 ]

The x object is free to interpret that however it wants, and the behaviour is typically (though not always) defined by the class x belongs to if x is a normal instance.

In this case it's returning the bit at a given index, equivalent to x & (1 << 6) >> 6.

Sometimes the [] method does several things:

string = "brackets"

# Retrieve a single character
string[1]
# => "r"

# Retrieve a substring
string[5,2]
# => "et"

# Perform a pattern match
string[/[^aeiou]+/]
# => "br"

This also does some pretty crazy things since you can apply it to a Proc as well:

fn = lambda { |x| x + 1 }

# Conventional (explicit) call
fn.call(2)
# => 3

# Square bracket method
fn[5]
# => 6

Since Ruby leans very heavily on Duck Typing, this means that you can write a Proc to fill in where you'd normally have a Hash or an Array and the method receiving your object is none the wiser.

It's this flexibility in leaving the meaning of x[...] for your own class instance x up to you that makes it pretty powerful.

For example:

class Bracketeer
  def [](i)
    "%d brackets" % i
  end
end

bracketeer = Bracketeer.new

bracketeer[6]
# => "6 brackets"

This simple notation often comes in handy when you're trying to create a minimal interface for a class of yours. In many cases you can use something simple like [] to replace what would be a more verbose method like find_by_id or cache_fetch.

Upvotes: 4

Jagtesh Chadha
Jagtesh Chadha

Reputation: 2672

It is returning the n'th bit as rightfully observed by @msergeant.

What this means is, for the number 33, its binary representation is:

Index : [7][6][5][4] [3][2][1][0]
Bits  :  0  0  1  0   0  0  0  1

Which explains the output:

irb(main):212:0> x[0]
=> 1
irb(main):213:0> x[1]
=> 0
irb(main):214:0> x[2]
=> 0

Upvotes: 1

David Hoelzer
David Hoelzer

Reputation: 16331

Certainly. You'll find that the manual is quite illuminating.

This is returning the binary bit for the bit position value as a zero or one.

Upvotes: 1

msergeant
msergeant

Reputation: 4801

The bracket operator gives you the nth bit of the binary representation:

http://ruby-doc.org/core-2.1.2/Fixnum.html#method-i-5B-5D

Upvotes: 5

Related Questions