-
Notifications
You must be signed in to change notification settings - Fork 21.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Refactor Hash#transform_values and Hash#transform_values! #16149
Conversation
Should we have a test for the |
I should also mention that I considered refactoring def transform_values(&block)
dup.transform_values!(&block)
end This would be more DRY but it also incurs a performance penalty (from duping) that I decided was not a worthwhile tradeoff. require 'benchmark/ips'
class Hash
def slow(&block)
dup.transform_values!(&block)
end
def fast(&block)
return enum_for(:fast) unless block_given?
result = self.class.new
each do |key, value|
result[key] = yield(value)
end
result
end
def transform_values!
return enum_for(:transform_values!) unless block_given?
each do |key, value|
self[key] = yield(value)
end
end
end
HASH = {a: 1, b: 2, c: 3}
Benchmark.ips do |x|
x.report("slow") { HASH.slow { |x| x * x } }
x.report("fast") { HASH.fast { |x| x * x } }
end
|
@matthewd Regardless of precedent, I’d argue that returning an |
@sferik oh, yes, I was just wondering about precedent for whether we bother writing a test for it; the behaviour itself is desirable. I believe the dup-based spelling, which was abandoned for performance, was the source of the unused '&block' wart, incidentally. |
Great work 👍 |
@matthewd I’ve added a couple tests and update the other extensions to |
@@ -6,7 +6,8 @@ class Hash | |||
# hash.transform_keys{ |key| key.to_s.upcase } | |||
# # => {"NAME"=>"Rob", "AGE"=>"28"} | |||
def transform_keys | |||
result = {} | |||
return enum_for(:transform_keys) unless block_given? | |||
result = self.class.new |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This sounds like it would have implications in the vicinity of HWIA...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you please state those implications in the form of a failing test?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was more just expressing subtle surprise that we didn't already have a test that expected HWIA#transform_keys to return a plain Hash. I have no actual objection to the more consistent behaviour.
LGTM |
Refactor Hash#transform_values and Hash#transform_values!
This patch makes two small changes to the new Active Support core extensions
Hash#transform_values
andHash#transform_values!
:These methods now return an
Enumerator
if no block is given. This makes them more consistent with otherEnumerable
methods and allows for method chaining, for example:Before this patch, such chaining would result in a
LocalJumpError: no block given
.Since the
&block
parameter is never referenced, I’ve removed it fromHash#transform_values
. This prevents a garbage Proc object from being constructed automatically on method invocation, resulting in measurably faster performance. Here is the benchmark I ran:References #15819. cc/ @guilleiguaran @rafaelfranca @sgrif