I’m currently reading through Ruby Under a Microscope: An Illustrated Guide to Ruby Internals, and when I tried to test the “hidden hash” in ruby 2.2, I got different results from the book.
In Ruby 2.2, it appears that the default arguments are used as one expects, without regard to the Hash monkey patch:
### CODE ###
class Hash
def key?(val)
false
end
end
def blah(a: 2, b: 5)
puts a + b
end
blah
blah(a:3)
blah(b:3)
blah(a:2000, b:2000)
### DISASSEMBLY ###
== disasm: @>==========
0000 trace 1 ( 1)
0002 putspecialobject 3
0004 putnil
0005 defineclass :Hash, , 0
0009 pop
0010 trace 1 ( 7)
0012 putspecialobject 1
0014 putspecialobject 2
0016 putobject :blah
0018 putiseq blah
0020 opt_send_without_block
0022 pop
0023 trace 1 ( 10)
0025 putself
0026 opt_send_without_block
0028 pop
0029 trace 1 ( 11)
0031 putself
0032 putobject 3
0034 opt_send_without_block
0036 pop
0037 trace 1 ( 12)
0039 putself
0040 putobject 3
0042 opt_send_without_block
0044 pop
0045 trace 1 ( 13)
0047 putself
0048 putobject 2000
0050 putobject 2000
0052 opt_send_without_block
0054 leave
== disasm: @>========
0000 trace 2 ( 1)
0002 trace 1 ( 2)
0004 putspecialobject 1
0006 putspecialobject 2
0008 putobject :key?
0010 putiseq key?
0012 opt_send_without_block
0014 trace 4 ( 5)
0016 leave ( 2)
== disasm: >================
local table (size: 2, argc: 1 [opts: 0, rest: -1, post: 0, block: -1, kw: -1@-1, kwrest: -1])
[ 2] val
0000 trace 8 ( 2)
0002 trace 1 ( 3)
0004 putobject false
0006 trace 16 ( 4)
0008 leave ( 3)
== disasm: >================
local table (size: 4, argc: 0 [opts: 0, rest: -1, post: 0, block: -1, kw: 2@0, kwrest: -1])
[ 4] a [ 3] b [ 2] ?
0000 trace 8 ( 7)
0002 trace 1 ( 8)
0004 putself
0005 getlocal_OP__WC__0 4
0007 getlocal_OP__WC__0 3
0009 opt_plus
0011 opt_send_without_block
0013 trace 16 ( 9)
0015 leave ( 8)
### RESULTS ###
7
8
5
4000
If I reset back to ruby 2.1, I get the unconditional usage of the default arguments:
### CODE ###
class Hash
def key?(val)
false
end
end
def blah(a: 2, b: 5)
puts a + b
end
blah
blah(a:3)
blah(b:3)
blah(a:2000, b:2000)
### DISASSEMBLY ###
== disasm: @>==========
0000 trace 1 ( 1)
0002 putspecialobject 3
0004 putnil
0005 defineclass :Hash, , 0
0009 pop
0010 trace 1 ( 7)
0012 putspecialobject 1
0014 putspecialobject 2
0016 putobject :blah
0018 putiseq blah
0020 opt_send_simple
0022 pop
0023 trace 1 ( 10)
0025 putself
0026 opt_send_simple
0028 pop
0029 trace 1 ( 11)
0031 putself
0032 putspecialobject 1
0034 putobject [:a, 3]
0036 opt_send_simple
0038 opt_send_simple
0040 pop
0041 trace 1 ( 12)
0043 putself
0044 putspecialobject 1
0046 putobject [:b, 3]
0048 opt_send_simple
0050 opt_send_simple
0052 pop
0053 trace 1 ( 13)
0055 putself
0056 putspecialobject 1
0058 putobject [:a, 2000, :b, 2000]
0060 opt_send_simple
0062 opt_send_simple
0064 leave
== disasm: @>========
0000 trace 2 ( 1)
0002 trace 1 ( 2)
0004 putspecialobject 1
0006 putspecialobject 2
0008 putobject :key?
0010 putiseq key?
0012 opt_send_simple
0014 trace 4 ( 5)
0016 leave ( 2)
== disasm: >================
local table (size: 2, argc: 1 [opts: 0, rest: -1, post: 0, block: -1, keyword: 0@3] s1)
[ 2] val
0000 trace 8 ( 2)
0002 trace 1 ( 3)
0004 putobject false
0006 trace 16 ( 4)
0008 leave ( 3)
== disasm: >================
local table (size: 4, argc: 0 [opts: 0, rest: -1, post: 0, block: -1, keyword: 2@2] s0)
[ 4] a [ 3] b [ 2] ?
0000 getlocal_OP__WC__0 2 ( 7)
0002 dup
0003 putobject :a
0005 opt_send_simple
0007 branchunless 18
0009 dup
0010 putobject :a
0012 opt_send_simple
0014 setlocal_OP__WC__0 4
0016 jump 22
0018 putobject 2
0020 setlocal_OP__WC__0 4
0022 dup
0023 putobject :b
0025 opt_send_simple
0027 branchunless 38
0029 dup
0030 putobject :b
0032 opt_send_simple
0034 setlocal_OP__WC__0 3
0036 jump 42
0038 putobject 5
0040 setlocal_OP__WC__0 3
0042 pop
0043 trace 8
0045 trace 1 ( 8)
0047 putself
0048 getlocal_OP__WC__0 4
0050 getlocal_OP__WC__0 3
0052 opt_plus
0054 opt_send_simple
0056 trace 16 ( 9)
0058 leave ( 8)
### RESULTS ###
7
7
7
7