Hi,
what would be the correct search expression for SmallLint to find the following pattern: condition ifTrue:[ ^result1 ] ifFalse:[ ^result2 ] or: condition ifTrue:[ ^result1 ]. ^result2 in order to replace it with ^condition ifTrue:[ result1 ] ifFalse:[ result2 ] I tested with VisualPart>>topComponent and interestingly the last form turned out to be around 10% faster than the first. In certain hot spots of an application, this could add up and make a difference. Apart from the performance aspect, the last form is also more functional style and less intention revealing (the intention being that "condition" actually decides upon the return value). Therefore I thought it would be a good idea to add this pattern to the Code Critic set of rules. The search pattern, of course, should allow any number of statements prior to result1/2. Any suggestions? Andre _______________________________________________ vwnc mailing list [hidden email] http://lists.cs.uiuc.edu/mailman/listinfo/vwnc |
search rule 1:
`@condition ifTrue:[ ^`@result1 ] ifFalse:[ ^`@result2 ] search rule 2: `@condition ifTrue:[ ^`@result1 ]. ^ `@result2 replace with: ^ `@condition ifTrue: [ `@result1 ] ifFalse: [ `@result2 ]. > Hi, > > what would be the correct search expression for SmallLint to find the > following pattern: > > condition > ifTrue:[ ^result1 ] > ifFalse:[ ^result2 ] > > or: > > condition > ifTrue:[ ^result1 ]. > ^result2 > > in order to replace it with > > ^condition > ifTrue:[ result1 ] > ifFalse:[ result2 ] > > I tested with VisualPart>>topComponent and interestingly the last form > turned out to be around 10% faster than the first. In certain hot > spots of an application, this could add up and make a difference. > Apart from the performance aspect, the last form is also more > functional style and less intention revealing (the intention being > that "condition" actually decides upon the return value). > > Therefore I thought it would be a good idea to add this pattern to the > Code Critic set of rules. The search pattern, of course, should allow > any number of statements prior to result1/2. > _______________________________________________ vwnc mailing list [hidden email] http://lists.cs.uiuc.edu/mailman/listinfo/vwnc |
Thanks Holger.
Me stupid. I missed the point that names used for matching are arbitrary. Expecting a syntax behind the names confused me. It's really simple. Now this is the complete rule, which also allows none or more statements before the returns: redundantReturns ^self createParseTreeRule: #( '`@condition ifTrue:[ `@.Statements1. ^`@result1 ] ifFalse: [ `@.Statements2. ^`@result2 ]' '`@condition ifTrue:[ `@.Statements1. ^`@result1 ]. ^`@result2' ) name: (#UnnecessaryReturns << #browser >> 'Unnecessary returns from both ifTrue:ifFalse blocks') asString Andre BTW: As a sidenote to the tools team: Gathering the rules from class protocol names seems a bit unintuitive and not robust wrt general refactoring (not found by looking for senders). I'd rather suggest to tag rule definitions with a pragma. -- Am 15.08.2010 um 00:25 schrieb Holger Kleinsorgen: > search rule 1: > > `@condition > ifTrue:[ ^`@result1 ] > ifFalse:[ ^`@result2 ] > > search rule 2: > > `@condition > ifTrue:[ ^`@result1 ]. > ^ `@result2 > > replace with: > > ^ `@condition > ifTrue: [ `@result1 ] > ifFalse: [ `@result2 ]. > > >> Hi, >> >> what would be the correct search expression for SmallLint to find the >> following pattern: >> >> condition >> ifTrue:[ ^result1 ] >> ifFalse:[ ^result2 ] >> >> or: >> >> condition >> ifTrue:[ ^result1 ]. >> ^result2 >> >> in order to replace it with >> >> ^condition >> ifTrue:[ result1 ] >> ifFalse:[ result2 ] >> >> I tested with VisualPart>>topComponent and interestingly the last >> form >> turned out to be around 10% faster than the first. In certain hot >> spots of an application, this could add up and make a difference. >> Apart from the performance aspect, the last form is also more >> functional style and less intention revealing (the intention being >> that "condition" actually decides upon the return value). >> >> Therefore I thought it would be a good idea to add this pattern to >> the >> Code Critic set of rules. The search pattern, of course, should allow >> any number of statements prior to result1/2. >> > > _______________________________________________ > vwnc mailing list > [hidden email] > http://lists.cs.uiuc.edu/mailman/listinfo/vwnc _______________________________________________ vwnc mailing list [hidden email] http://lists.cs.uiuc.edu/mailman/listinfo/vwnc |
On 8/15/2010 5:16 AM, andermoo wrote:
> Me stupid. I missed the point that names used for matching are > arbitrary. Expecting a syntax behind the names confused me. It's > really simple. Now this is the complete rule, which also allows none > or more statements before the returns: > > redundantReturns > ^self > createParseTreeRule: #( > '`@condition ifTrue:[ `@.Statements1. ^`@result1 ] ifFalse: > [ `@.Statements2. ^`@result2 ]' > '`@condition ifTrue:[ `@.Statements1. ^`@result1 ]. ^`@result2' > ) > name: (#UnnecessaryReturns << #browser >> 'Unnecessary returns from > both ifTrue:ifFalse blocks') asString The second expression only matches two statements instead of a list of statements that ends with the two statements. To fix that you need to add "|`@temps| `@.Statements0." to the beginning of your expression. If you want to transform the multiple returns into a single return, you can look at the expressions in the InlineMethodRefactoring class. In particular, look at normalizeIfTrues and normalizeReturns. The normalizeIfTrues method transforms your second case into your first and the normalizeReturns transforms the first case into a single ifTrue:ifFalse: return. You may want to change the patterns in normalizeIfTrues somewhat as they will eliminate guard clauses. John Brant _______________________________________________ vwnc mailing list [hidden email] http://lists.cs.uiuc.edu/mailman/listinfo/vwnc |
In reply to this post by andermoo
Hi!
On 14.08.2010 19:36, andermoo wrote: > Hi, > > what would be the correct search expression for SmallLint to find the > following pattern: > > condition > ifTrue:[ ^result1 ] > ifFalse:[ ^result2 ] > > or: > > condition > ifTrue:[ ^result1 ]. > ^result2 > > in order to replace it with > > ^condition > ifTrue:[ result1 ] > ifFalse:[ result2 ] > > I tested with VisualPart>>topComponent and interestingly the last form > turned out to be around 10% faster than the first. In certain hot > spots of an application, this could add up and make a difference. > Apart from the performance aspect, the last form is also more > functional style and less intention revealing (the intention being > that "condition" actually decides upon the return value). Without questioning the style aspect, I wonder how you measured that 10% performance boost. Because in the simplest form of method, like ^ boolean ifTrue: [ 1 ] ifFalse: [ 2 ] the bytecodes for its variations (two alternate returns or two returns with a guard clause) are exactly the same: 1 <00> push inst 0 2 <C1> jump false 5 3 <4A> push 1 4 <65> return 5 <4B> push 2 6 <65> return for the three variants. The only measurable execution time differences even depend on order of execution after creation of the object understanding this method. Regards Jan _______________________________________________ vwnc mailing list [hidden email] http://lists.cs.uiuc.edu/mailman/listinfo/vwnc |
Am 16.08.2010 um 07:35 schrieb Jan Weerts: > Without questioning the style aspect, I wonder how you measured that > 10% performance boost. Because in the simplest form of method, like > ^ boolean > ifTrue: [ 1 ] > ifFalse: [ 2 ] > the bytecodes for its variations (two alternate returns or two > returns with a guard clause) are exactly the same: > 1 <00> push inst 0 > 2 <C1> jump false 5 > 3 <4A> push 1 > 4 <65> return > 5 <4B> push 2 > 6 <65> return > for the three variants. The only measurable execution time > differences even depend on order of execution after creation of the > object understanding this method. > > Regards > Jan Hi Jan, thanks for pointing this out. Ha! I fell for a simple measurement mistake. I repeated the measurement this morning, and it still seemed to be there, which completely puzzled me. I picked a deeply nested VisualPart from an open window with the inspector and did the test for #VisualPart>>topComponent: Time millisecondsToRun:[ 100000000 timesRepeat:[ self topComponent ]]. Ran that test 10 times and took the average. The difference is a little less than yesterday (~8%), but it's still there and reproduceable. Considering the identical bytecodes, there should not be any difference, or at least occur for both variants with the same probability. Now, my mistake was to not take the garbage collector into account. As I always tested in the same order, for the second test, the GC had more work to do! I missed to check the most obvious first, the bytecodes, before doing any measurement. I should stick with my apps and GUIs and keep my hands off this kind of minimalist tweaking ;-) Andre _______________________________________________ vwnc mailing list [hidden email] http://lists.cs.uiuc.edu/mailman/listinfo/vwnc |
Free forum by Nabble | Edit this page |