Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Using Object#in? and Object#either? in various places
There're a lot of places in Rails source code which make a lot of sense to switching to Object#in? or Object#either? instead of using [].include?.
- Loading branch information
Showing
44 changed files
with
108 additions
and
52 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
a9f3c9d
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 commit breaks actionpack tests on 1.9.2. Please fix. ❤️
I'm happy about adding convenience methods, but is it really necessary to make sweeping changes to rails internals like this?
a9f3c9d
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.
Rails should use its own best practices, but yes, we should make a habit of running the suite under both 1.8.7 and 1.9.2 now to catch any bugs.
a9f3c9d
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.
@dhh I don't think we've properly done the du-diligence required to award
Object#in?
andObject#either?
the title of "best practice".Here's why:
either?
uses varargs, which costs us an extra array allocationMany of the changes made in this commit probably weren't in performance hotspots, but I don't think anyone has done research on that. Especially the changes in actionpack worry me.
a9f3c9d
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.
1: This point is self-evident to me by comparing before/after code using #in? vs #include?
2: This doesn't change that. People are already doing inline arrays to use with include? -- see the code changed in this example.
3: I'm willing to make this sacrifice for the added expressiveness.
4: See 3.
Re: performance, I'd rather we take the general principle that we'll write the best, most beautiful code we can first and then back out of it when it's proven to be a problem.
a9f3c9d
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.
+1
a9f3c9d
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.
re #2, the code changed in this example is my point. By switching to
either?
we've removed thetLBRACK
nodes from the AST:Now there is no possibility to cache the arrays in the AST.
I agree we should write the best looking code and deal with perf stuff later. I just can't help from commenting because the perf degradations are so apparent to me and the supposed readability win seem minimal in comparison. :-(
Anyway, once the tests pass, I'll stop complaining. ;-)
a9f3c9d
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.
Can you come up with a case that shows the performance degradation (or maybe someone else can?)? I'm all for beauty, but sure, if there's a noticeable (even if smallish) ding to performance, it's not worth it at the framework level. Also, we can switch that one to .in?([ :references, :belongs_to ]) and we're still ahead. But let's first see some data showing this to be a problem.
a9f3c9d
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.
Just calling 2 methods vs calling 1 method is a perf ding (on mri). I didn't think we'd need benchmarks to prove that.
Only frequent code paths are important. But like I said, I don't think these changes are in hotspots. I am just afraid to add this many changes at once!
a9f3c9d
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.
While it's certainly up to you, I'd suggest not using this idiom if there are only 2 values being tested for. The performance difference between just doing the 2 comparisons in the if and calling out to #either? is radically different. Additionally, it can be just as easy to read and write.
a9f3c9d
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.
@dhh Here is a benchmark for ya: https://gist.github.com/912835
a9f3c9d
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.
@tenderlove I'm fixing the test case now. I was running the isolated test locally myself and saw that error too, but I thought somebody broke it first because I never be able to run the whole green test suite. Shame on me.
The reason I propose the change internal core was 1) Someone said that if I'm going to add a method to core_ext I should be able to show that Rails would be benefits by it too. And 2) Would be the fact that you can see a lot of use cases in those files.
From @evanphx benchmark, That's pretty massive. Is there any way I could improve the method?
a9f3c9d
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.
After further discussion with the core team, I decide to back off a bit and I'm going to change back to using
[].include?
in a lot of places. This seems like a tradeoff between performance and readable code.a9f3c9d
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.
From what I can tell, the uses of
in?
in Rails itself are mostly limited to a small operand. Thus, I was hoping that "unrolling" it a bit to would help performance on small inputs. Sadly, it's actually worse on Ruby 1.9.2.a9f3c9d
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 looks like hardly a difference at all at 50% unless it's sitting smack in the middle of a hotspot code path where it's the main time consumer. The vast majority of these changes are in tests or completely non-critical areas. I'd do some quick benches on 3 points: The callback change, the mime respond, and the mapper. Or you could remove those three in a round of premature optimization and leave the other 40 changes in place.