-
Notifications
You must be signed in to change notification settings - Fork 21.9k
Pass symbol as an argument instead of a block #16833
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
Conversation
cc16185
to
a86d7e0
Compare
We're generally neutral to negative on en masse cosmetic changes (considering few/none of these are in perf hotspots). But it feels like a good time to clean house and sweep out some cobwebs, too. Maybe after 4-2-stable branches? |
@jeremy I included the benchmarks to try to make the case that these changes were not purely cosmetic. I understand the folly of micro-benchmarks but these 20% performance improvements, spread over 250 spots in the code, could add up to real-world benefits for Rails users, depending on their usage of the framework. For example, I wouldn’t be surprised if Since I believe this is a real performance win, I’d obviously prefer it to be included in version 4.2.0 but I’d also be happy if this was merged after the 4.2.0 release, if that is preferred for some reason. |
If we're going to merge it, we're probably better off having it in 4-2-stable. Otherwise, it'll cause (admittedly, minor) backport pain for the entire life of 5.x. Edit: On the other hand, as we're already planning a load of rearrangement post-4.2 (kwargs, etc), maybe it is actually better grouped with that -- and leave 4.2 looking more like 4.1. |
@jeremy I’m not sure whether you italicized en masse for emphasis or because it has a foreign origin (French, I believe). Anyway, in case this pull request would be accepted if it was broken up into smaller commits (e.g. one for each Rails component) that could be cherry-picked, I’d be happy to make that change. Just say the word. |
@thedarkone Thanks for the history lesson. I didn’t know about those commits. Since the reason those commits were made has not been valid for a while, I think it’s high time to reverse them. |
👍 for merging this after the 4-2-stable branch is created. |
@rafaelfranca Sounds good. I’ll rebase after |
Great! I'll leave the tab open in my browser so I'll not forgot about it 😄 |
96af639
to
320dd3d
Compare
I’m all for the consistency and conciseness arguments of this pull request. But regarding the performance argument, you need to consider the size of the enumerables we’re looping. Here are my results of your benchmark code, run with Ruby 2.1.2p95
Ruby 2.0.0p451
Ruby 1.9.3p545
So, for very small arrays, |
@bquorning Thanks for running your own benchmarks and pointing this out. I’d argue that for small enumerables, performance is less critical. I was optimizing to make the worst-case scenario 20% faster, even if that comes at the cost of making the best-case scenario 10% slower. I stand by that trade-off but it might be worth looking at the individual cases and applying this change more selectively, rather than across the board. In the example I used above (iterating over I decided to optimize for the worst-case scenario and apply the change consistently throughout the codebase but I’m happy to consider each case individually and make a judgment about whether the enumerable is likely to be greater or less than 5. |
I agree. The point of my benchmarks was just to highlight that the 20% performance improvement doesn’t apply for all use cases. I’m fine with changing to use |
ruby 2.1.3p242 class Foo
def initialize
@foo = 1
@bar = 2
@dar = 3
end
end
@foo = Foo.new
Benchmark.ips do |x|
x.report("block") {
@foo.instance_variables.map { |var| var.to_s }
}
x.report("to_proc") {
@foo.instance_variables.map(&:to_s)
}
x.compare!
end
|
@huacnlee You seem to be raising the same objection as @bquorning. For small values of require 'benchmark/ips'
class Foo
def initialize
@a, @b, @c, @d, @e, @f, @g, @h, @i = 1, 2, 3, 4, 5, 6, 7, 8, 9
end
end
@foo = Foo.new
Benchmark.ips do |x|
x.report('block') {
@foo.instance_variables.map { |var| var.to_s }
}
x.report('to_proc') {
@foo.instance_variables.map(&:to_s)
}
x.compare!
end
|
f0b4f75
to
9124555
Compare
9124555
to
e46a2d7
Compare
e46a2d7
to
d1374f9
Compare
@rafaelfranca Can this be merged now? |
Pass symbol as an argument instead of a block
@rafaelfranca Wow! That was quick. Thanks! |
Thanks 😃 |
Using Ruby’s
Symbol#to_proc
is considerably more concise than using block syntax. It’s also about 20% faster (see benchmarks below).Symbol#to_proc
is already used in many places throughout the Rails codebase, but not everywhere. This patch makes the codebase more consistent and concise. In some cases, it reduces the number of lines of code. For example, inrailties/lib/rails/application/routes_reloader.rb
:becomes:
The net result is 30 fewer lines of code.
For those who don’t know the history,
Symbol#to_proc
was originally part of Active Support, before being merged into the Ruby language in version 1.9 (and back-ported to 1.8.7). The Active Support implementation was slightly slower than using a block but the C implementation in MRI is considerably faster.Benchmark
Ruby 2.1.2p95
Ruby 2.0.0p481
Ruby 1.9.3p545