Hi Levente,<br>
<br>
whoops, this had escaped my attention, sorry! Anyway, there is (almost 2 year old :D) Collections-ct.877 in the inbox - do you think we can merge it like this or have you got any further tips for me? :-)<br>
<br>
Best,<br>
Christoph<br>
<br>
<font color="#808080">---<br>
</font><font color="#808080"><i>Sent from </i></font><font color="#808080"><i><a href="https://github.com/hpi-swa-lab/squeak-inbox-talk"><u><font color="#808080">Squeak Inbox Talk</font></u></a></i></font><br>
<br>
On 2020-02-17T20:23:37+01:00, leves@caesar.elte.hu wrote:<br>
<br>
> Hi Christoph,<br>
> <br>
> On Mon, 17 Feb 2020, Thiede, Christoph wrote:<br>
> <br>
> > <br>
> > > The current Spur VM makes x >= 1 about 1.5x faster than x >= y, because it has more type information available.<br>
> > <br>
> > <br>
> > Wow, this is interesting.<br>
> > However, I found out it is even faster to use #to:do: (4.2 ms vs. 5.19 ms). I will send this soon to the inbox.<br>
> > <br>
> > Just one other question before: I just discovered that we have #detect:ifNone: and also #find:ifNone: and #findBinary:ifNone:. #ifAbsent: rather appears to go with #at:, i. e. lookup operations, whereas #ifNone: goes with<br>
> > search operations. Are you still sure that we shouldn't name the thing #findFirst:ifNone:?<br>
> <br>
> I don't have #find:ifNone: in my image. SequenceableCollection <br>
> understands #detect:ifNone:, #findBinary:ifNone:, and <br>
> #findBinaryIndex:ifNone:.<br>
> If you search for *ifNone: and *ifAbsent:, you'll find that the latter is <br>
> more common, but seeing the number of implementors of these methods, I <br>
> suppose it boils down to personal preference.<br>
> <br>
> <br>
> Levente<br>
> <br>
> > <br>
> > Best,<br>
> > Christoph<br>
> > <br>
> > _________________________________________________________________________________________________________________________________________________________________________________________________________________________________<br>
> > Von: Squeak-dev <squeak-dev-bounces at lists.squeakfoundation.org> im Auftrag von Levente Uzonyi <leves at caesar.elte.hu><br>
> > Gesendet: Montag, 17. Februar 2020 15:10:10<br>
> > An: The general-purpose Squeak developers list<br>
> > Betreff: Re: [squeak-dev] The Inbox: Collections-ct.875.mcz  <br>
> > Hi Christoph,<br>
> > <br>
> > On Mon, 17 Feb 2020, Thiede, Christoph wrote:<br>
> > <br>
> > ><br>
> > > Hi Levente,<br>
> > ><br>
> > ><br>
> > > alright, I'll try to measure and optimize them again.<br>
> > ><br>
> > ><br>
> > > > Two things I saw and you didn't mention are block creation<br>
> > ><br>
> > ><br>
> > > You mean that "ifNone: [0]"? One could replace it with "ifNone: 0" to avoid duplication.<br>
> > <br>
> > That's a possible way, but there's an even better one: put the actual<br>
> > implementation into #findFirst:startingAt:, and let<br>
> > #findFirst:startingAt:ifAbsent: use it. Just like how it's done in the<br>
> > #indexOf:* methods.<br>
> > <br>
> > ><br>
> > > > and introduction of non-jittable comparison.<br>
> > ><br>
> > > What are you referring to?<br>
> > <br>
> > The current Spur VM makes x >= 1 about 1.5x faster than x >= y, because it<br>
> > has more type information available.<br>
> > <br>
> > Another possible optimization in #findFirst: is to store #size in a<br>
> > temporary instead of accessing it in each iteration.<br>
> > <br>
> > Levente<br>
> > <br>
> > ><br>
> > > Best,<br>
> > > Christoph<br>
> > ><br>
> > >________________________________________________________________________________________________________________________________________________________________________________________________________________________________<br>
> > _<br>
> > > Von: Squeak-dev <squeak-dev-bounces at lists.squeakfoundation.org> im Auftrag von Levente Uzonyi <leves at caesar.elte.hu><br>
> > > Gesendet: Montag, 17. Februar 2020 01:00:11<br>
> > > An: The general-purpose Squeak developers list<br>
> > > Betreff: Re: [squeak-dev] The Inbox: Collections-ct.875.mcz  <br>
> > > Hi Christoph,<br>
> > ><br>
> > > On Sun, 16 Feb 2020, Thiede, Christoph wrote:<br>
> > ><br>
> > > ><br>
> > > > Hi Levente,<br>
> > > ><br>
> > > ><br>
> > > > thanks for the suggestions.<br>
> > > ><br>
> > > ><br>
> > > > > And one more thing: These method resemble #indexOf:* methods, so I think #ifAbsent: is a better choice than #ifNone:.<br>
> > > ><br>
> > > ><br>
> > > > Agreed :-)<br>
> > > ><br>
> > > > > I suggest keeping the all method comments<br>
> > > ><br>
> > > > Personally, I see little value in documenting a one-liner. Documentation is useful for explaining and optimized method that does not provide the typical Smalltalk readability. Plus, they all need to be maintained ...<br>
> > ><br>
> > > If one sees #findLast: being sent somewhere, and one doesn't know what it<br>
> > > does, with your changes, it means looking up the implementors three times<br>
> > > to get to the actual implementation and comment.<br>
> > ><br>
> > > ><br>
> > > > > measuring the performance impact of the rewrite.<br>
> > > ><br>
> > > > What is the critical point here?<br>
> > > > Of course, the stack will be a little higher, but the asymptotic cost does not change. We only evaluate anotherBlock at the end instead of returning 0.<br>
> > ><br>
> > > Two things I saw and you didn't mention are block creation and<br>
> > > introduction of non-jittable comparison.<br>
> > ><br>
> > > ><br>
> > > > Please do not misunderstand me: I honor optimizing critical Smalltalk methods, but I always strive to avoid premature optimization.<br>
> > ><br>
> > > In my opinion, generic library methods like these should be optimized by<br>
> > > definition.<br>
> > ><br>
> > > Calling premature optimization means that you assume that if these methods<br>
> > > were written in a more optimal way, then their complexity and/or<br>
> > > legibility would be worse.<br>
> > > Have a look at #indexOf:*, and you'll see that's not the case.<br>
> > ><br>
> > > > Should we maybe establish to practice to store such benchmarks somewhere in the trunk so that not every willing contributor needs to write them again?<br>
> > ><br>
> > > I think methods like these don't change often enough (presumably they<br>
> > > never change) to justify storing benchmarks for them.<br>
> > ><br>
> > ><br>
> > > Levente<br>
> > ><br>
> > > ><br>
> > > > Best,<br>
> > > > Christoph<br>
> > > ><br>
> > >>_______________________________________________________________________________________________________________________________________________________________________________________________________________________________<br>
> > _<br>
> > > _<br>
> > > > Von: Squeak-dev <squeak-dev-bounces at lists.squeakfoundation.org> im Auftrag von Levente Uzonyi <leves at caesar.elte.hu><br>
> > > > Gesendet: Sonntag, 16. Februar 2020 22:47:10<br>
> > > > An: The general-purpose Squeak developers list<br>
> > > > Betreff: Re: [squeak-dev] The Inbox: Collections-ct.875.mcz  <br>
> > > > And one more thing: These method resemble #indexOf:* methods, so I think<br>
> > > > #ifAbsent: is a better choice than #ifNone:.<br>
> > > ><br>
> > > > Levente<br>
> > > ><br>
> > > > On Sun, 16 Feb 2020, Levente Uzonyi wrote:<br>
> > > ><br>
> > > > > Hi Christoph,<br>
> > > > ><br>
> > > > > I suggest keeping the all method comments, and measuring the performance<br>
> > > > > impact of the rewrite.<br>
> > > > ><br>
> > > > > Levente<br>
> > > > ><br>
> > > > > On Sun, 16 Feb 2020, commits at source.squeak.org wrote:<br>
> > > > ><br>
> > > > >> A new version of Collections was added to project The Inbox:<br>
> > > > >> http://source.squeak.org/inbox/Collections-ct.875.mcz<br>
> > > > >><br>
> > > > >> ==================== Summary ====================<br>
> > > > >><br>
> > > > >> Name: Collections-ct.875<br>
> > > > >> Author: ct<br>
> > > > >> Time: 16 February 2020, 3:32:23.116 pm<br>
> > > > >> UUID: 61ea773b-1408-c040-a712-09238ee6fe2f<br>
> > > > >> Ancestors: Collections-topa.873<br>
> > > > >><br>
> > > > >> Extends and realigns version of #findFirst: and #findLast:.<br>
> > > > >><br>
> > > > >> =============== Diff against Collections-topa.873 ===============<br>
> > > > >><br>
> > > > >> Item was changed:<br>
> > > > >>  ----- Method: SequenceableCollection>>findFirst: (in category<br>
> > > > > 'enumerating') -----<br>
> > > > >>  findFirst: aBlock<br>
> > > > >> -     "Return the index of my first element for which aBlock evaluates as<br>
> > > > > true."<br>
> > > > >><br>
> > > > >> +     ^ self findFirst: aBlock startingAt: 1!<br>
> > > > >> -     | index |<br>
> > > > >> -     index := 0.<br>
> > > > >> -     [(index := index + 1) <= self size] whileTrue:<br>
> > > > >> -             [(aBlock value: (self at: index)) ifTrue: [^index]].<br>
> > > > >> -     ^ 0!<br>
> > > > >><br>
> > > > >> Item was added:<br>
> > > > >> + ----- Method: SequenceableCollection>>findFirst:ifNone: (in category<br>
> > > > > 'enumerating') -----<br>
> > > > >> + findFirst: aBlock ifNone: anotherBlock<br>
> > > > >> +<br>
> > > > >> +     ^ self findFirst: aBlock startingAt: 1 ifNone: anotherBlock!<br>
> > > > >><br>
> > > > >> Item was added:<br>
> > > > >> + ----- Method: SequenceableCollection>>findFirst:startingAt: (in category<br>
> > > > > 'enumerating') -----<br>
> > > > >> + findFirst: aBlock startingAt: minIndex<br>
> > > > >> +<br>
> > > > >> +     ^ self findFirst: aBlock startingAt: minIndex ifNone: [0]!<br>
> > > > >><br>
> > > > >> Item was added:<br>
> > > > >> + ----- Method: SequenceableCollection>>findFirst:startingAt:ifNone: (in<br>
> > > > > category 'enumerating') -----<br>
> > > > >> + findFirst: aBlock startingAt: minIndex ifNone: anotherBlock<br>
> > > > >> +     "Return the index of my first element with index >= minIndex for<br>
> > > > > which aBlock evaluates as true. If no element is found, return the value of<br>
> > > > > anotherBlock."<br>
> > > > >> +<br>
> > > > >> +     | index |<br>
> > > > >> +     index := minIndex - 1.<br>
> > > > >> +     [(index := index + 1) <= self size] whileTrue:<br>
> > > > >> +             [(aBlock value: (self at: index)) ifTrue: [^index]].<br>
> > > > >> +     ^ anotherBlock value!<br>
> > > > >><br>
> > > > >> Item was changed:<br>
> > > > >>  ----- Method: SequenceableCollection>>findLast: (in category<br>
> > > > > 'enumerating') -----<br>
> > > > >>  findLast: aBlock<br>
> > > > >> -     "Return the index of my last element for which aBlock evaluates as<br>
> > > > > true."<br>
> > > > >><br>
> > > > >> +     ^ self findLast: aBlock startingAt: 1!<br>
> > > > >> -     | index |<br>
> > > > >> -     index := self size + 1.<br>
> > > > >> -     [(index := index - 1) >= 1] whileTrue:<br>
> > > > >> -             [(aBlock value: (self at: index)) ifTrue: [^index]].<br>
> > > > >> -     ^ 0!<br>
> > > > >><br>
> > > > >> Item was added:<br>
> > > > >> + ----- Method: SequenceableCollection>>findLast:ifNone: (in category<br>
> > > > > 'enumerating') -----<br>
> > > > >> + findLast: aBlock ifNone: anotherBlock<br>
> > > > >> +<br>
> > > > >> +     ^ self findLast: aBlock startingAt: 1 ifNone: anotherBlock!<br>
> > > > >><br>
> > > > >> Item was changed:<br>
> > > > >>  ----- Method: SequenceableCollection>>findLast:startingAt: (in category<br>
> > > > > 'enumerating') -----<br>
> > > > >> + findLast: aBlock startingAt: minIndex<br>
> > > > >> - findLast: aBlock startingAt: i<br>
> > > > >> -     "Return the index of my last element with index >= i for which aBlock<br>
> > > > > evaluates as true."<br>
> > > > >><br>
> > > > >> +     ^ self findLast: aBlock startingAt: minIndex ifNone: [0]!<br>
> > > > >> -     | index |<br>
> > > > >> -     index := self size + 1.<br>
> > > > >> -     [(index := index - 1) >= i] whileTrue:<br>
> > > > >> -             [(aBlock value: (self at: index)) ifTrue: [^index]].<br>
> > > > >> -     ^ 0!<br>
> > > > >><br>
> > > > >> Item was added:<br>
> > > > >> + ----- Method: SequenceableCollection>>findLast:startingAt:ifNone: (in<br>
> > > > > category 'enumerating') -----<br>
> > > > >> + findLast: aBlock startingAt: minIndex ifNone: anotherBlock<br>
> > > > >> +     "Return the index of my last element with index >= minIndex for which<br>
> > > > > aBlock evaluates as true.  If no element is found, return the value of<br>
> > > > > anotherBlock."<br>
> > > > >> +<br>
> > > > >> +     | index |<br>
> > > > >> +     index := self size + 1.<br>
> > > > >> +     [(index := index - 1) >= minIndex] whileTrue:<br>
> > > > >> +             [(aBlock value: (self at: index)) ifTrue: [^index]].<br>
> > > > >> +     ^ anotherBlock value!<br>
> > > > ><br>
> > > > ><br>
> > > ><br>
> > > ><br>
> > > ><br>
> > ><br>
> > ><br>
> > <br>
> ><br>
> <br>