Ruby: Square Brackets vs. Array.new

Mon 03 April 2017

Earlier today I did a code review and saw my coworker using Array.new to create an empty array. I know that this gives the same return value as the literal constructor [], as shown below.

irb(main):001:0> Array.new
=> []
irb(main):002:0> []
=> []

I was moving to the next line when a little voice in my head asked "but are they the same internally?" I took a look at the Ruby source code and to my surprise, the two approaches use different functions in array.c

# Square brackets
rb_define_singleton_method(rb_cArray, "[]", rb_ary_s_create, -1);
# Array.new
rb_define_method(rb_cArray, "initialize", rb_ary_initialize, -1);

The Ruby disassembler also shows the differences, using some small test programs against Ruby 2.3.3

# square_brackets.rb
test = []
#array_new.rb
test = Array.new
$ ruby --dump insns square_brackets.rb
== disasm: #<ISeq:<main>@square_brackets.rb>============================
local table (size: 2, argc: 0 [opts: 0, rest: -1, post: 0, block: -1, kw: -1@-1, kwrest: -1])
[ 2] test
0000 trace            1                                               (   1)
0002 newarray         0
0004 dup
0005 setlocal_OP__WC__0 2
0007 leave
$ ruby --dump insns array_new.rb
== disasm: #<ISeq:<main>@array_new.rb>==================================
local table (size: 2, argc: 0 [opts: 0, rest: -1, post: 0, block: -1, kw: -1@-1, kwrest: -1])
[ 2] test
0000 trace            1                                               (   1)
0002 getinlinecache   9, <is:0>
0005 getconstant      :Array
0007 setinlinecache   <is:0>
0009 opt_send_without_block <callinfo!mid:new, argc:0, ARGS_SIMPLE>, <callcache>
0012 dup
0013 setlocal_OP__WC__0 2
0015 leave

So I’m think in testing the behaviour and writing this article, it far outweighs any performance benefit I’ve ever gotten from using brackets. Still, what you don’t know about the internals of a language can bite you, and it doesn’t hurt to scrutinize your assumptions, no matter how basic.

blogroll

social