diff options
author | Jean Boussier <jean.boussier@gmail.com> | 2023-01-11 10:08:52 +0100 |
---|---|---|
committer | git <svn-admin@ruby-lang.org> | 2023-01-11 09:26:08 +0000 |
commit | e85ef212de98c817154ab62ae2d03508c512107e (patch) | |
tree | 237a3996528b528782c9835039fcae28bee1b2cf | |
parent | 8c2b6926d2c6ba0317fcccb08c8b6657d4f0730c (diff) | |
download | ruby-e85ef212de98c817154ab62ae2d03508c512107e.tar.gz |
[ruby/set] Avoid the `block or return` pattern to save Proc allocations
Using the block param in a boolean context like this cause it to be
allocated.
Using it with an `if` or `unless` was optimized in 3.2
(https://github.com/ruby/ruby/pull/6286) but using it with `or`
or `and` wasn't.
```ruby
def foo(&block)
block or return 1
end
puts RubyVM::InstructionSequence.of(method(:foo)).disasm
== disasm: #<ISeq:foo@(irb):11 (11,0)-(13,3)> (catch: false)
local table (size: 1, argc: 0 [opts: 0, rest: -1, post: 0, block: 0, kw: -1@-1, kwrest: -1])
[ 1] block@0<Block>
0000 getblockparam block@0, 0 ( 12)[LiCa]
0003 dup
0004 branchif 10
0006 pop
0007 putobject_INT2FIX_1_
0008 leave [Re]
0009 putnil
0010 leave
```
versus
```
def foo(&block)
return 1 if block
end
puts RubyVM::InstructionSequence.of(method(:foo)).disasm
== disasm: #<ISeq:foo@(irb):15 (15,0)-(17,3)> (catch: false)
local table (size: 1, argc: 0 [opts: 0, rest: -1, post: 0, block: 0, kw: -1@-1, kwrest: -1])
[ 1] block@0<Block>
0000 getblockparamproxy block@0, 0 ( 16)[LiCa]
0003 branchunless 7
0005 putobject_INT2FIX_1_
0006 leave ( 17)[Re]
0007 putnil ( 16)
0008 leave
```
https://github.com/ruby/set/commit/e89da977d4
-rw-r--r-- | lib/set.rb | 6 |
1 files changed, 3 insertions, 3 deletions
diff --git a/lib/set.rb b/lib/set.rb index df1e68d081..a515dacb0e 100644 --- a/lib/set.rb +++ b/lib/set.rb @@ -507,7 +507,7 @@ class Set # the element as parameter. Returns an enumerator if no block is # given. def each(&block) - block or return enum_for(__method__) { size } + block_given? or return enum_for(__method__) { size } @hash.each_key(&block) self end @@ -582,7 +582,7 @@ class Set # Equivalent to Set#delete_if, but returns nil if no changes were # made. Returns an enumerator if no block is given. def reject!(&block) - block or return enum_for(__method__) { size } + block_given? or return enum_for(__method__) { size } n = size delete_if(&block) self if size != n @@ -591,7 +591,7 @@ class Set # Equivalent to Set#keep_if, but returns nil if no changes were # made. Returns an enumerator if no block is given. def select!(&block) - block or return enum_for(__method__) { size } + block_given? or return enum_for(__method__) { size } n = size keep_if(&block) self if size != n |