# About Instantiating Ruby Arrays Using Literal Notation

Last week, I discovered an oddity about Ruby’s literal array syntax in conjunction with hashes. The following (simplified) test is syntactically valid Ruby code:

 1 2 3 4 5 describe do let(:h) { { "foo" => "bar" } } let(:a) { [h] } it { a.should =~ ["foo" => "bar"] } end 

Do you see what’s strange about the syntax? After running the test, I was about to add a second expectation and noticed the missing curly braces in line number 4. As it turns out, the following statement evaluates to true:

 1 2 3 ~ ➜ irb 2.0.0-p247 :001 > [{ "foo" => "bar" }] == ["foo" => "bar"] => true 

For me, this was a surprise, since I would have expected some kind a syntax error (maybe unexpected token '=>'). Further experiments revealed the following:

 1 2 3 4 5 2.0.0-p247 :002 > [123, { "foo" => "bar" }] == [123, "foo" => "bar"] => true 2.0.0-p247 :003 > [{ "foo" => "bar" }, 123] == ["foo" => "bar", 123] SyntaxError: (irb):3: syntax error, unexpected ']', expecting => from /Users/cs/.rvm/rubies/ruby-2.0.0-p247/bin/irb:16:in
' 

Literal array definitions, seem to behave exactly like ordinary method invocations: The last argument is interpreted as a hash – even without the curly braces. In the Rails community, this behaviour is widely known as the options hash.

Now, every Ruby method call must have a receiver. If no explicit receiver has been specified, the implicit receiver is self. This suggets, that there should be a method [] defined on self. Let’s check:

 1 2 3 4 5 2.0.0-p247 :004 > self.method(:[]) NameError: undefined method []' for class Object' from (irb):8:in method' from (irb):8 from /Users/cs/.rvm/rubies/ruby-2.0.0-p247/bin/irb:16:in
' 

Strangely, [] is not defined. Hmmm.

By consulting the standard library documentation, I disovered the method Array.[]. Except for the explicit receiver, that class method seems to be functionally equivalent to the literal syntax:

 1 2 3 4 5 6 2.0.0-p247 :004 > Array[] => [] 2.0.0-p247 :005 > Array[123] => [123] 2.0.0-p247 :006 > Array[123, "bar" => "foo"] => [123, {"bar"=>"foo"}] 

Just out of curiousity, it would be interesting to find out wether Array.[] gets called when instantiating a new array with literal syntax. Luckily, Ruby’s meta-programming features make it easy to rewrite existing methods:

 1 2 3 4 5 6 7 8 9 10 11 12 13 2.0.0-p247 :007 > class < alias_method :original_square_brackets, :[] 2.0.0-p247 :009?> def [](*args) 2.0.0-p247 :010?> puts "Array.[] has been called!" 2.0.0-p247 :011?> original_square_brackets(*args) 2.0.0-p247 :012?> end 2.0.0-p247 :013?> end => nil 2.0.0-p247 :014 > Array[1, 2, 3] Array.[] has been called! => [1, 2, 3] 2.0.0-p247 :015 > [1, 2, 3] => [1, 2, 3] 

Line number 9 clearly demonstrates that Array.[] has been rewritten as intended. However, nothing has been printed during instantiation of the literal array in line number 12.

## Conclusion

Even though, [] is behaving exactly like Array.[] (which is an ordinary method), it’s not possible to change []. In comparision, Array.[] can be overwritten easily. My guess is, that the interpreter has been optimized to directly use the native implementation of [] and skip the usual method lookup process. Magic ;)

Did you know about [{"foo" => "bar"}] == ["bar" => "foo"]`?