On Thu, Dec 3, 2015 at 4:51 PM, Ben Coman <[hidden email]> wrote: On Fri, Dec 4, 2015 at 3:26 AM, Chris Cunningham Yeah. Forgot the parenthesis. 1 + 2@2 is the same as (1 + 2) @ 2. My eye sees the closeness of 2@2 as a point - not as a binary message (which it obviously is). So, never mind. -cbc |
In reply to this post by Ben Coman
I agree. If I want to sum something other than a collection of numbers I’ll happily provide the block for that summation (I wouldn’t even expect strings to be summable to be honest. Why would you have a collection of numbers that are strings…? And if you really have one, you should convert it explicitly so that another person reading your code knows what’s going on.)
While I think you might be on to something, I think we should take small steps. I’d be happy already if we can just get rid of one superfluous method and provide a better API without starting to think about the deeper semantics. Also, I think there’s a reason why Aconcagua is an external package: developers usually are happy to work with numbers (which are already objects in Smalltalk anyway) and they’re fast.
|
In reply to this post by Max Leske
So what is the conclusion?
I like the idea of Esteban M to have iterator because it moves some behavior out of core classes. [[[ aCollection arithmetic sum: [...] or.... aCollection arithmetic avg. ]]] |
I would like to wrap up this discussion.
While I think that iterators are an intriguing idea I also believe that they are beyond the scope of this issue. If anybody wants to follow up on iterators (or unit types for that matter) please start a new thread / issue. I propose to use Sven’s version for #sum:ifEmpty:. The result would be these three methods: sum ^ self sum: [ :each | each ] ifEmpty: [ 0 ] sum: aBlock ^ self sum: aBlock ifEmpty: [ self errorEmptyCollection ] sum: aBlock ifEmpty: emptyBlock | sum sample | self isEmpty ifTrue: [ ^ emptyBlock value ]. sample := self anyOne. sum := self inject: sample into: [ :accum :each | accum + (aBlock value: each) ]. ^ sum - sample I’ve attached a couple of benchmark results below. To me they show that 1. the new implementation is maybe a tiny bit slower but insignificantly so (if you’re going for performance you’ll probably write your own optimised version anyway) 2. there is no need to duplicate the code (like #sum and #sum: currently do). It’s perfectly fine to delegate to #sum:ifEmpty: In addition to the above changes I would like to remove #detectSum: (-> #sum:) and #sumNumbers (-> #sum). Note that once we agree on changing this API, we will need to also change #detectMin:, #detectMax:, #min, #max as well as all overrides (e.g. RunArray, Interval) of these and of #sum et. al. to stay consistent. The changes would of course be in line with this change, such that every operation has a unary selector with a sensible default, one that takes a block and throws an error for empty collections and a third that takes a block for the iteration and one for the empty case. Please cast your vote for these changes: 1. Do you agree to changing #sum and #sum: in the suggested way? 2. Do you agree to the removal of #detectSum:? 3. Do you agree to the removal of #sumNumbers? 4. Do you agree that the #max and #min selectors also need to be adapted? Thanks for you help. Cheers, Max Benchmarks ============ (Note that these aren’t very good benchmarks. There’s quite some variation on each run.) Machine: MacBook Pro (15-inch, Early 2011) CPU: 2.2 GHz Intel Core i7 Memory: 8 GB 1333 MHz DDR3 Disk: APPLE SSD TS512C (500 GB) Benchmarks of the current versions: [ (1 to: 1000000) asArray sum ] benchFor: 10 seconds. 75 iterations, 7.470 per second [ (1 to: 1000000) asArray sum: [ :e | e ] ] benchFor: 10 seconds. 72 iterations, 7.128 per second [ (1 to: 100) asArray sum ] benchFor: 10 seconds. 1,189,477 iterations, 118,912 per second [ (1 to: 100) asArray sum: [ :e | e ] ] benchFor: 10 seconds. 1,171,467 iterations, 117,112 per second Benchmarks of the new versions: [ (1 to: 1000000) asArray sum ] benchFor: 10 seconds. 73 iterations, 7.244 per second [ (1 to: 1000000) asArray sum: [ :e | e ] ] benchFor: 10 seconds. 75 iterations, 7.480 per second [ (1 to: 1000000) asArray sum: [ :e | e ] ifEmpty: [ 0 ] ] benchFor: 10 seconds. 72 iterations, 7.141 per second [ (1 to: 100) asArray sum ] benchFor: 10 seconds. 1,115,827 iterations, 111,560 per second [ (1 to: 100) asArray sum: [ :e | e ] ] benchFor: 10 seconds. 1,154,595 iterations, 115,425 per second [ (1 to: 100) asArray sum: [ :e | e ] ifEmpty: [ 0 ] ] benchFor: 10 seconds. 1,102,358 iterations, 110,203 per second |
Max, sum: aBlock ifEmpty: emptyBlock needs to obtain the sample evaluating the block. sum: aBlock ifEmpty: emptyBlock | sum sample | self isEmpty ifTrue: [ ^ emptyBlock value ]. sample := aBlock value: self anyOne. sum := self inject: sample into: [ :accum :each | accum + (aBlock value: each) ]. ^ sum - sample On Sun, Dec 20, 2015 at 8:59 AM, Max Leske <[hidden email]> wrote:
|
Thanks! Missed that.
|
In reply to this post by Max Leske
> On 20 Dec 2015, at 12:59, Max Leske <[hidden email]> wrote: > > I would like to wrap up this discussion. Good idea. >> On 05 Dec 2015, at 18:14, stepharo <[hidden email]> wrote: >> >> So what is the conclusion? >> I like the idea of Esteban M to have iterator because it moves some behavior out of core classes. >> >> [[[ >> >> aCollection arithmetic sum: [...] or.... aCollection >> arithmetic avg. >> >> ]]] >> > > While I think that iterators are an intriguing idea I also believe that they are beyond the scope of this issue. If anybody wants to follow up on iterators (or unit types for that matter) please start a new thread / issue. > > > I propose to use Sven’s version for #sum:ifEmpty:. The result would be these three methods: > > sum > ^ self > sum: [ :each | each ] > ifEmpty: [ 0 ] > > sum: aBlock > ^ self > sum: aBlock > ifEmpty: [ self errorEmptyCollection ] > > sum: aBlock ifEmpty: emptyBlock > | sum sample | > self isEmpty ifTrue: [ ^ emptyBlock value ]. > sample := self anyOne. > sum := self > inject: sample > into: [ :accum :each | accum + (aBlock value: each) ]. > ^ sum - sample > > > I’ve attached a couple of benchmark results below. To me they show that > 1. the new implementation is maybe a tiny bit slower but insignificantly so (if you’re going for performance you’ll probably write your own optimised version anyway) > 2. there is no need to duplicate the code (like #sum and #sum: currently do). It’s perfectly fine to delegate to #sum:ifEmpty: > > > > In addition to the above changes I would like to remove #detectSum: (-> #sum:) and #sumNumbers (-> #sum). > > > Note that once we agree on changing this API, we will need to also change #detectMin:, #detectMax:, #min, #max as well as all overrides (e.g. RunArray, Interval) of these and of #sum et. al. to stay consistent. The changes would of course be in line with this change, such that every operation has a unary selector with a sensible default, one that takes a block and throws an error for empty collections and a third that takes a block for the iteration and one for the empty case. Excellent summary, thanks. > Please cast your vote for these changes: > > 1. Do you agree to changing #sum and #sum: in the suggested way? yes > 2. Do you agree to the removal of #detectSum:? yes > 3. Do you agree to the removal of #sumNumbers? yes > 4. Do you agree that the #max and #min selectors also need to be adapted? probably yes. > Thanks for you help. > > Cheers, > Max > > > > > > Benchmarks > ============ > (Note that these aren’t very good benchmarks. There’s quite some variation on each run.) You should exclude your setup out of your actual benchmark, like this: | numbers | numbers := (1 to: 1000000) asArray. [ numbers sum ] benchFor: 10 seconds. "a BenchmarkResult(126 iterations in 10 seconds 77 milliseconds. 12.504 per second)" > Machine: > MacBook Pro (15-inch, Early 2011) > CPU: 2.2 GHz Intel Core i7 > Memory: 8 GB 1333 MHz DDR3 > Disk: APPLE SSD TS512C (500 GB) > > > Benchmarks of the current versions: > > [ (1 to: 1000000) asArray sum ] benchFor: 10 seconds. > 75 iterations, 7.470 per second > > [ (1 to: 1000000) asArray sum: [ :e | e ] ] benchFor: 10 seconds. > 72 iterations, 7.128 per second > > > [ (1 to: 100) asArray sum ] benchFor: 10 seconds. > 1,189,477 iterations, 118,912 per second > > > [ (1 to: 100) asArray sum: [ :e | e ] ] benchFor: 10 seconds. > 1,171,467 iterations, 117,112 per second > > > > Benchmarks of the new versions: > > [ (1 to: 1000000) asArray sum ] benchFor: 10 seconds. > 73 iterations, 7.244 per second > > [ (1 to: 1000000) asArray sum: [ :e | e ] ] benchFor: 10 seconds. > 75 iterations, 7.480 per second > > [ (1 to: 1000000) asArray sum: [ :e | e ] ifEmpty: [ 0 ] ] benchFor: 10 seconds. > 72 iterations, 7.141 per second > > > [ (1 to: 100) asArray sum ] benchFor: 10 seconds. > 1,115,827 iterations, 111,560 per second > > [ (1 to: 100) asArray sum: [ :e | e ] ] benchFor: 10 seconds. > 1,154,595 iterations, 115,425 per second > > [ (1 to: 100) asArray sum: [ :e | e ] ifEmpty: [ 0 ] ] benchFor: 10 seconds. > 1,102,358 iterations, 110,203 per second > |
In reply to this post by Max Leske
Hi,
Could we not have sum, but sumNumbers instead? So, we would end up with: sum:ifEmpty: sum: (with error) sumNumbers (without error) From the outside, #sum: looks like it should parameterize #sum, but the implementation is actually different. So, given that in this implementation #sum is not a special case of #sum: the two should be named differently to reflect that difference. Hence my proposal is to keep #sumNumbers instead of #sum. Cheers, Doru > On Dec 20, 2015, at 1:47 PM, Max Leske <[hidden email]> wrote: > >> >> On 20 Dec 2015, at 13:43, Gabriel Cotelli <[hidden email]> wrote: >> >> Max, >> >> sum: aBlock ifEmpty: emptyBlock needs to obtain the sample evaluating the block. >> >> sum: aBlock ifEmpty: emptyBlock >> | sum sample | >> self isEmpty ifTrue: [ ^ emptyBlock value ]. >> sample := aBlock value: self anyOne. >> sum := self >> inject: sample >> into: [ :accum :each | accum + (aBlock value: each) ]. >> ^ sum - sample > > > Thanks! Missed that. > >> >> On Sun, Dec 20, 2015 at 8:59 AM, Max Leske <[hidden email]> wrote: >> I would like to wrap up this discussion. >> >> >>> On 05 Dec 2015, at 18:14, stepharo <[hidden email]> wrote: >>> >>> So what is the conclusion? >>> I like the idea of Esteban M to have iterator because it moves some behavior out of core classes. >>> >>> [[[ >>> >>> aCollection arithmetic sum: [...] or.... aCollection >>> arithmetic avg. >>> >>> ]]] >>> >> >> While I think that iterators are an intriguing idea I also believe that they are beyond the scope of this issue. If anybody wants to follow up on iterators (or unit types for that matter) please start a new thread / issue. >> >> >> I propose to use Sven’s version for #sum:ifEmpty:. The result would be these three methods: >> >> sum >> ^ self >> sum: [ :each | each ] >> ifEmpty: [ 0 ] >> >> sum: aBlock >> ^ self >> sum: aBlock >> ifEmpty: [ self errorEmptyCollection ] >> >> sum: aBlock ifEmpty: emptyBlock >> | sum sample | >> self isEmpty ifTrue: [ ^ emptyBlock value ]. >> sample := self anyOne. >> sum := self >> inject: sample >> into: [ :accum :each | accum + (aBlock value: each) ]. >> ^ sum - sample >> >> >> I’ve attached a couple of benchmark results below. To me they show that >> 1. the new implementation is maybe a tiny bit slower but insignificantly so (if you’re going for performance you’ll probably write your own optimised version anyway) >> 2. there is no need to duplicate the code (like #sum and #sum: currently do). It’s perfectly fine to delegate to #sum:ifEmpty: >> >> >> >> In addition to the above changes I would like to remove #detectSum: (-> #sum:) and #sumNumbers (-> #sum). >> >> >> Note that once we agree on changing this API, we will need to also change #detectMin:, #detectMax:, #min, #max as well as all overrides (e.g. RunArray, Interval) of these and of #sum et. al. to stay consistent. The changes would of course be in line with this change, such that every operation has a unary selector with a sensible default, one that takes a block and throws an error for empty collections and a third that takes a block for the iteration and one for the empty case. >> >> >> Please cast your vote for these changes: >> >> 1. Do you agree to changing #sum and #sum: in the suggested way? >> >> 2. Do you agree to the removal of #detectSum:? >> >> 3. Do you agree to the removal of #sumNumbers? >> >> 4. Do you agree that the #max and #min selectors also need to be adapted? >> >> >> >> Thanks for you help. >> >> Cheers, >> Max >> >> >> >> >> >> Benchmarks >> ============ >> (Note that these aren’t very good benchmarks. There’s quite some variation on each run.) >> >> >> Machine: >> MacBook Pro (15-inch, Early 2011) >> CPU: 2.2 GHz Intel Core i7 >> Memory: 8 GB 1333 MHz DDR3 >> Disk: APPLE SSD TS512C (500 GB) >> >> >> Benchmarks of the current versions: >> >> [ (1 to: 1000000) asArray sum ] benchFor: 10 seconds. >> 75 iterations, 7.470 per second >> >> [ (1 to: 1000000) asArray sum: [ :e | e ] ] benchFor: 10 seconds. >> 72 iterations, 7.128 per second >> >> >> [ (1 to: 100) asArray sum ] benchFor: 10 seconds. >> 1,189,477 iterations, 118,912 per second >> >> >> [ (1 to: 100) asArray sum: [ :e | e ] ] benchFor: 10 seconds. >> 1,171,467 iterations, 117,112 per second >> >> >> >> Benchmarks of the new versions: >> >> [ (1 to: 1000000) asArray sum ] benchFor: 10 seconds. >> 73 iterations, 7.244 per second >> >> [ (1 to: 1000000) asArray sum: [ :e | e ] ] benchFor: 10 seconds. >> 75 iterations, 7.480 per second >> >> [ (1 to: 1000000) asArray sum: [ :e | e ] ifEmpty: [ 0 ] ] benchFor: 10 seconds. >> 72 iterations, 7.141 per second >> >> >> [ (1 to: 100) asArray sum ] benchFor: 10 seconds. >> 1,115,827 iterations, 111,560 per second >> >> [ (1 to: 100) asArray sum: [ :e | e ] ] benchFor: 10 seconds. >> 1,154,595 iterations, 115,425 per second >> >> [ (1 to: 100) asArray sum: [ :e | e ] ifEmpty: [ 0 ] ] benchFor: 10 seconds. >> 1,102,358 iterations, 110,203 per second -- www.tudorgirba.com www.feenk.com "There are no old things, there are only old ways of looking at them." |
In reply to this post by Sven Van Caekenberghe-2
Updated benchmarks with pre-calculated collection of numbers (as suggested by Sven): Benchmarks of the current versions: [ (1 to: 1000000) asArray sum ] benchFor: 10 seconds. 124 iterations, 12.389 per second [ (1 to: 1000000) asArray sum: [ :e | e ] ] benchFor: 10 seconds. 109 iterations, 10.801 per second) [ (1 to: 100) asArray sum ] benchFor: 10 seconds. 4,166,154 iterations, 416,532 per second [ (1 to: 100) asArray sum: [ :e | e ] ] benchFor: 10 seconds. 3,115,121 iterations, 311,481 per second Benchmarks of the new versions: [ (1 to: 1000000) asArray sum ] benchFor: 10 seconds. 125 iterations, 12.490 per second [ (1 to: 1000000) asArray sum: [ :e | e ] ] benchFor: 10 seconds. 119 iterations, 11.842 per second [ (1 to: 1000000) asArray sum: [ :e | e ] ifEmpty: [ 0 ] ] benchFor: 10 seconds. 130 iterations, 12.947 per second [ (1 to: 100) asArray sum ] benchFor: 10 seconds. 2,985,085 iterations, 298,449 per second [ (1 to: 100) asArray sum: [ :e | e ] ] benchFor: 10 seconds. 3,260,280 iterations, 325,963 per second [ (1 to: 100) asArray sum: [ :e | e ] ifEmpty: [ 0 ] ] benchFor: 10 seconds. 3,143,812 iterations, 314,287 per second The benchmark for #sum suggests that there’s indeed a benefit of duplicating the code for that particular case (the delegations would make #sum 30% slower). I still think we should use delegation there instead of duplicate code. #sum is not a “critical” method in my opinion. Cheers, Max
|
In reply to this post by Tudor Girba-2
> On 20 Dec 2015, at 14:10, Tudor Girba <[hidden email]> wrote: > > Hi, > > Could we not have sum, but sumNumbers instead? So, we would end up with: > > sum:ifEmpty: > sum: (with error) > sumNumbers (without error) > > From the outside, #sum: looks like it should parameterize #sum, but the implementation is actually different. So, given that in this implementation #sum is not a special case of #sum: the two should be named differently to reflect that difference. Hence my proposal is to keep #sumNumbers instead of #sum. I could live with that. We would sacrifice the beautiful selector #sum for the more intention revealing #sumNumbers. I think that makes sense. Concerning the #min and #max methods that means we’d end up with e.g. #minNumbers, #min: and #min:ifEmpty: etc. > > Cheers, > Doru > > >> On Dec 20, 2015, at 1:47 PM, Max Leske <[hidden email]> wrote: >> >>> >>> On 20 Dec 2015, at 13:43, Gabriel Cotelli <[hidden email]> wrote: >>> >>> Max, >>> >>> sum: aBlock ifEmpty: emptyBlock needs to obtain the sample evaluating the block. >>> >>> sum: aBlock ifEmpty: emptyBlock >>> | sum sample | >>> self isEmpty ifTrue: [ ^ emptyBlock value ]. >>> sample := aBlock value: self anyOne. >>> sum := self >>> inject: sample >>> into: [ :accum :each | accum + (aBlock value: each) ]. >>> ^ sum - sample >> >> >> Thanks! Missed that. >> >>> >>> On Sun, Dec 20, 2015 at 8:59 AM, Max Leske <[hidden email]> wrote: >>> I would like to wrap up this discussion. >>> >>> >>>> On 05 Dec 2015, at 18:14, stepharo <[hidden email]> wrote: >>>> >>>> So what is the conclusion? >>>> I like the idea of Esteban M to have iterator because it moves some behavior out of core classes. >>>> >>>> [[[ >>>> >>>> aCollection arithmetic sum: [...] or.... aCollection >>>> arithmetic avg. >>>> >>>> ]]] >>>> >>> >>> While I think that iterators are an intriguing idea I also believe that they are beyond the scope of this issue. If anybody wants to follow up on iterators (or unit types for that matter) please start a new thread / issue. >>> >>> >>> I propose to use Sven’s version for #sum:ifEmpty:. The result would be these three methods: >>> >>> sum >>> ^ self >>> sum: [ :each | each ] >>> ifEmpty: [ 0 ] >>> >>> sum: aBlock >>> ^ self >>> sum: aBlock >>> ifEmpty: [ self errorEmptyCollection ] >>> >>> sum: aBlock ifEmpty: emptyBlock >>> | sum sample | >>> self isEmpty ifTrue: [ ^ emptyBlock value ]. >>> sample := self anyOne. >>> sum := self >>> inject: sample >>> into: [ :accum :each | accum + (aBlock value: each) ]. >>> ^ sum - sample >>> >>> >>> I’ve attached a couple of benchmark results below. To me they show that >>> 1. the new implementation is maybe a tiny bit slower but insignificantly so (if you’re going for performance you’ll probably write your own optimised version anyway) >>> 2. there is no need to duplicate the code (like #sum and #sum: currently do). It’s perfectly fine to delegate to #sum:ifEmpty: >>> >>> >>> >>> In addition to the above changes I would like to remove #detectSum: (-> #sum:) and #sumNumbers (-> #sum). >>> >>> >>> Note that once we agree on changing this API, we will need to also change #detectMin:, #detectMax:, #min, #max as well as all overrides (e.g. RunArray, Interval) of these and of #sum et. al. to stay consistent. The changes would of course be in line with this change, such that every operation has a unary selector with a sensible default, one that takes a block and throws an error for empty collections and a third that takes a block for the iteration and one for the empty case. >>> >>> >>> Please cast your vote for these changes: >>> >>> 1. Do you agree to changing #sum and #sum: in the suggested way? >>> >>> 2. Do you agree to the removal of #detectSum:? >>> >>> 3. Do you agree to the removal of #sumNumbers? >>> >>> 4. Do you agree that the #max and #min selectors also need to be adapted? >>> >>> >>> >>> Thanks for you help. >>> >>> Cheers, >>> Max >>> >>> >>> >>> >>> >>> Benchmarks >>> ============ >>> (Note that these aren’t very good benchmarks. There’s quite some variation on each run.) >>> >>> >>> Machine: >>> MacBook Pro (15-inch, Early 2011) >>> CPU: 2.2 GHz Intel Core i7 >>> Memory: 8 GB 1333 MHz DDR3 >>> Disk: APPLE SSD TS512C (500 GB) >>> >>> >>> Benchmarks of the current versions: >>> >>> [ (1 to: 1000000) asArray sum ] benchFor: 10 seconds. >>> 75 iterations, 7.470 per second >>> >>> [ (1 to: 1000000) asArray sum: [ :e | e ] ] benchFor: 10 seconds. >>> 72 iterations, 7.128 per second >>> >>> >>> [ (1 to: 100) asArray sum ] benchFor: 10 seconds. >>> 1,189,477 iterations, 118,912 per second >>> >>> >>> [ (1 to: 100) asArray sum: [ :e | e ] ] benchFor: 10 seconds. >>> 1,171,467 iterations, 117,112 per second >>> >>> >>> >>> Benchmarks of the new versions: >>> >>> [ (1 to: 1000000) asArray sum ] benchFor: 10 seconds. >>> 73 iterations, 7.244 per second >>> >>> [ (1 to: 1000000) asArray sum: [ :e | e ] ] benchFor: 10 seconds. >>> 75 iterations, 7.480 per second >>> >>> [ (1 to: 1000000) asArray sum: [ :e | e ] ifEmpty: [ 0 ] ] benchFor: 10 seconds. >>> 72 iterations, 7.141 per second >>> >>> >>> [ (1 to: 100) asArray sum ] benchFor: 10 seconds. >>> 1,115,827 iterations, 111,560 per second >>> >>> [ (1 to: 100) asArray sum: [ :e | e ] ] benchFor: 10 seconds. >>> 1,154,595 iterations, 115,425 per second >>> >>> [ (1 to: 100) asArray sum: [ :e | e ] ifEmpty: [ 0 ] ] benchFor: 10 seconds. >>> 1,102,358 iterations, 110,203 per second > > -- > www.tudorgirba.com > www.feenk.com > > "There are no old things, there are only old ways of looking at them." > > > > > |
Hi,
> On Dec 20, 2015, at 2:30 PM, Max Leske <[hidden email]> wrote: > > >> On 20 Dec 2015, at 14:10, Tudor Girba <[hidden email]> wrote: >> >> Hi, >> >> Could we not have sum, but sumNumbers instead? So, we would end up with: >> >> sum:ifEmpty: >> sum: (with error) >> sumNumbers (without error) >> >> From the outside, #sum: looks like it should parameterize #sum, but the implementation is actually different. So, given that in this implementation #sum is not a special case of #sum: the two should be named differently to reflect that difference. Hence my proposal is to keep #sumNumbers instead of #sum. > > I could live with that. We would sacrifice the beautiful selector #sum for the more intention revealing #sumNumbers. I think that makes sense. > > Concerning the #min and #max methods that means we’d end up with e.g. #minNumbers, #min: and #min:ifEmpty: etc. Yes. Doru > >> >> Cheers, >> Doru >> >> >>> On Dec 20, 2015, at 1:47 PM, Max Leske <[hidden email]> wrote: >>> >>>> >>>> On 20 Dec 2015, at 13:43, Gabriel Cotelli <[hidden email]> wrote: >>>> >>>> Max, >>>> >>>> sum: aBlock ifEmpty: emptyBlock needs to obtain the sample evaluating the block. >>>> >>>> sum: aBlock ifEmpty: emptyBlock >>>> | sum sample | >>>> self isEmpty ifTrue: [ ^ emptyBlock value ]. >>>> sample := aBlock value: self anyOne. >>>> sum := self >>>> inject: sample >>>> into: [ :accum :each | accum + (aBlock value: each) ]. >>>> ^ sum - sample >>> >>> >>> Thanks! Missed that. >>> >>>> >>>> On Sun, Dec 20, 2015 at 8:59 AM, Max Leske <[hidden email]> wrote: >>>> I would like to wrap up this discussion. >>>> >>>> >>>>> On 05 Dec 2015, at 18:14, stepharo <[hidden email]> wrote: >>>>> >>>>> So what is the conclusion? >>>>> I like the idea of Esteban M to have iterator because it moves some behavior out of core classes. >>>>> >>>>> [[[ >>>>> >>>>> aCollection arithmetic sum: [...] or.... aCollection >>>>> arithmetic avg. >>>>> >>>>> ]]] >>>>> >>>> >>>> While I think that iterators are an intriguing idea I also believe that they are beyond the scope of this issue. If anybody wants to follow up on iterators (or unit types for that matter) please start a new thread / issue. >>>> >>>> >>>> I propose to use Sven’s version for #sum:ifEmpty:. The result would be these three methods: >>>> >>>> sum >>>> ^ self >>>> sum: [ :each | each ] >>>> ifEmpty: [ 0 ] >>>> >>>> sum: aBlock >>>> ^ self >>>> sum: aBlock >>>> ifEmpty: [ self errorEmptyCollection ] >>>> >>>> sum: aBlock ifEmpty: emptyBlock >>>> | sum sample | >>>> self isEmpty ifTrue: [ ^ emptyBlock value ]. >>>> sample := self anyOne. >>>> sum := self >>>> inject: sample >>>> into: [ :accum :each | accum + (aBlock value: each) ]. >>>> ^ sum - sample >>>> >>>> >>>> I’ve attached a couple of benchmark results below. To me they show that >>>> 1. the new implementation is maybe a tiny bit slower but insignificantly so (if you’re going for performance you’ll probably write your own optimised version anyway) >>>> 2. there is no need to duplicate the code (like #sum and #sum: currently do). It’s perfectly fine to delegate to #sum:ifEmpty: >>>> >>>> >>>> >>>> In addition to the above changes I would like to remove #detectSum: (-> #sum:) and #sumNumbers (-> #sum). >>>> >>>> >>>> Note that once we agree on changing this API, we will need to also change #detectMin:, #detectMax:, #min, #max as well as all overrides (e.g. RunArray, Interval) of these and of #sum et. al. to stay consistent. The changes would of course be in line with this change, such that every operation has a unary selector with a sensible default, one that takes a block and throws an error for empty collections and a third that takes a block for the iteration and one for the empty case. >>>> >>>> >>>> Please cast your vote for these changes: >>>> >>>> 1. Do you agree to changing #sum and #sum: in the suggested way? >>>> >>>> 2. Do you agree to the removal of #detectSum:? >>>> >>>> 3. Do you agree to the removal of #sumNumbers? >>>> >>>> 4. Do you agree that the #max and #min selectors also need to be adapted? >>>> >>>> >>>> >>>> Thanks for you help. >>>> >>>> Cheers, >>>> Max >>>> >>>> >>>> >>>> >>>> >>>> Benchmarks >>>> ============ >>>> (Note that these aren’t very good benchmarks. There’s quite some variation on each run.) >>>> >>>> >>>> Machine: >>>> MacBook Pro (15-inch, Early 2011) >>>> CPU: 2.2 GHz Intel Core i7 >>>> Memory: 8 GB 1333 MHz DDR3 >>>> Disk: APPLE SSD TS512C (500 GB) >>>> >>>> >>>> Benchmarks of the current versions: >>>> >>>> [ (1 to: 1000000) asArray sum ] benchFor: 10 seconds. >>>> 75 iterations, 7.470 per second >>>> >>>> [ (1 to: 1000000) asArray sum: [ :e | e ] ] benchFor: 10 seconds. >>>> 72 iterations, 7.128 per second >>>> >>>> >>>> [ (1 to: 100) asArray sum ] benchFor: 10 seconds. >>>> 1,189,477 iterations, 118,912 per second >>>> >>>> >>>> [ (1 to: 100) asArray sum: [ :e | e ] ] benchFor: 10 seconds. >>>> 1,171,467 iterations, 117,112 per second >>>> >>>> >>>> >>>> Benchmarks of the new versions: >>>> >>>> [ (1 to: 1000000) asArray sum ] benchFor: 10 seconds. >>>> 73 iterations, 7.244 per second >>>> >>>> [ (1 to: 1000000) asArray sum: [ :e | e ] ] benchFor: 10 seconds. >>>> 75 iterations, 7.480 per second >>>> >>>> [ (1 to: 1000000) asArray sum: [ :e | e ] ifEmpty: [ 0 ] ] benchFor: 10 seconds. >>>> 72 iterations, 7.141 per second >>>> >>>> >>>> [ (1 to: 100) asArray sum ] benchFor: 10 seconds. >>>> 1,115,827 iterations, 111,560 per second >>>> >>>> [ (1 to: 100) asArray sum: [ :e | e ] ] benchFor: 10 seconds. >>>> 1,154,595 iterations, 115,425 per second >>>> >>>> [ (1 to: 100) asArray sum: [ :e | e ] ifEmpty: [ 0 ] ] benchFor: 10 seconds. >>>> 1,102,358 iterations, 110,203 per second >> >> -- >> www.tudorgirba.com >> www.feenk.com >> >> "There are no old things, there are only old ways of looking at them." >> >> >> >> >> > > -- www.tudorgirba.com www.feenk.com "If you can't say why something is relevant, it probably isn't." |
In reply to this post by Tudor Girba-2
Doru,
For me this whole discussion started because you (the standpoint that you take) hijacked the best selector (#sum) for a use case that is much less common than adding a collection of numbers which should give 0 when empty (you hijack it by not wanting to return 0, which I totally understand, but doing so you redefine the meaning/semantics). Max's point is to make everything more consistent and remove some API. I support that too. Now, I like Max's proposal. But, you know, my conclusion when the thread ended was that it might be better to throw all these selectors away, since #inject:into: covers most use cases at least as well and at least as clear. Sven > On 20 Dec 2015, at 14:10, Tudor Girba <[hidden email]> wrote: > > Hi, > > Could we not have sum, but sumNumbers instead? So, we would end up with: > > sum:ifEmpty: > sum: (with error) > sumNumbers (without error) > > From the outside, #sum: looks like it should parameterize #sum, but the implementation is actually different. So, given that in this implementation #sum is not a special case of #sum: the two should be named differently to reflect that difference. Hence my proposal is to keep #sumNumbers instead of #sum. > > Cheers, > Doru > > >> On Dec 20, 2015, at 1:47 PM, Max Leske <[hidden email]> wrote: >> >>> >>> On 20 Dec 2015, at 13:43, Gabriel Cotelli <[hidden email]> wrote: >>> >>> Max, >>> >>> sum: aBlock ifEmpty: emptyBlock needs to obtain the sample evaluating the block. >>> >>> sum: aBlock ifEmpty: emptyBlock >>> | sum sample | >>> self isEmpty ifTrue: [ ^ emptyBlock value ]. >>> sample := aBlock value: self anyOne. >>> sum := self >>> inject: sample >>> into: [ :accum :each | accum + (aBlock value: each) ]. >>> ^ sum - sample >> >> >> Thanks! Missed that. >> >>> >>> On Sun, Dec 20, 2015 at 8:59 AM, Max Leske <[hidden email]> wrote: >>> I would like to wrap up this discussion. >>> >>> >>>> On 05 Dec 2015, at 18:14, stepharo <[hidden email]> wrote: >>>> >>>> So what is the conclusion? >>>> I like the idea of Esteban M to have iterator because it moves some behavior out of core classes. >>>> >>>> [[[ >>>> >>>> aCollection arithmetic sum: [...] or.... aCollection >>>> arithmetic avg. >>>> >>>> ]]] >>>> >>> >>> While I think that iterators are an intriguing idea I also believe that they are beyond the scope of this issue. If anybody wants to follow up on iterators (or unit types for that matter) please start a new thread / issue. >>> >>> >>> I propose to use Sven’s version for #sum:ifEmpty:. The result would be these three methods: >>> >>> sum >>> ^ self >>> sum: [ :each | each ] >>> ifEmpty: [ 0 ] >>> >>> sum: aBlock >>> ^ self >>> sum: aBlock >>> ifEmpty: [ self errorEmptyCollection ] >>> >>> sum: aBlock ifEmpty: emptyBlock >>> | sum sample | >>> self isEmpty ifTrue: [ ^ emptyBlock value ]. >>> sample := self anyOne. >>> sum := self >>> inject: sample >>> into: [ :accum :each | accum + (aBlock value: each) ]. >>> ^ sum - sample >>> >>> >>> I’ve attached a couple of benchmark results below. To me they show that >>> 1. the new implementation is maybe a tiny bit slower but insignificantly so (if you’re going for performance you’ll probably write your own optimised version anyway) >>> 2. there is no need to duplicate the code (like #sum and #sum: currently do). It’s perfectly fine to delegate to #sum:ifEmpty: >>> >>> >>> >>> In addition to the above changes I would like to remove #detectSum: (-> #sum:) and #sumNumbers (-> #sum). >>> >>> >>> Note that once we agree on changing this API, we will need to also change #detectMin:, #detectMax:, #min, #max as well as all overrides (e.g. RunArray, Interval) of these and of #sum et. al. to stay consistent. The changes would of course be in line with this change, such that every operation has a unary selector with a sensible default, one that takes a block and throws an error for empty collections and a third that takes a block for the iteration and one for the empty case. >>> >>> >>> Please cast your vote for these changes: >>> >>> 1. Do you agree to changing #sum and #sum: in the suggested way? >>> >>> 2. Do you agree to the removal of #detectSum:? >>> >>> 3. Do you agree to the removal of #sumNumbers? >>> >>> 4. Do you agree that the #max and #min selectors also need to be adapted? >>> >>> >>> >>> Thanks for you help. >>> >>> Cheers, >>> Max >>> >>> >>> >>> >>> >>> Benchmarks >>> ============ >>> (Note that these aren’t very good benchmarks. There’s quite some variation on each run.) >>> >>> >>> Machine: >>> MacBook Pro (15-inch, Early 2011) >>> CPU: 2.2 GHz Intel Core i7 >>> Memory: 8 GB 1333 MHz DDR3 >>> Disk: APPLE SSD TS512C (500 GB) >>> >>> >>> Benchmarks of the current versions: >>> >>> [ (1 to: 1000000) asArray sum ] benchFor: 10 seconds. >>> 75 iterations, 7.470 per second >>> >>> [ (1 to: 1000000) asArray sum: [ :e | e ] ] benchFor: 10 seconds. >>> 72 iterations, 7.128 per second >>> >>> >>> [ (1 to: 100) asArray sum ] benchFor: 10 seconds. >>> 1,189,477 iterations, 118,912 per second >>> >>> >>> [ (1 to: 100) asArray sum: [ :e | e ] ] benchFor: 10 seconds. >>> 1,171,467 iterations, 117,112 per second >>> >>> >>> >>> Benchmarks of the new versions: >>> >>> [ (1 to: 1000000) asArray sum ] benchFor: 10 seconds. >>> 73 iterations, 7.244 per second >>> >>> [ (1 to: 1000000) asArray sum: [ :e | e ] ] benchFor: 10 seconds. >>> 75 iterations, 7.480 per second >>> >>> [ (1 to: 1000000) asArray sum: [ :e | e ] ifEmpty: [ 0 ] ] benchFor: 10 seconds. >>> 72 iterations, 7.141 per second >>> >>> >>> [ (1 to: 100) asArray sum ] benchFor: 10 seconds. >>> 1,115,827 iterations, 111,560 per second >>> >>> [ (1 to: 100) asArray sum: [ :e | e ] ] benchFor: 10 seconds. >>> 1,154,595 iterations, 115,425 per second >>> >>> [ (1 to: 100) asArray sum: [ :e | e ] ifEmpty: [ 0 ] ] benchFor: 10 seconds. >>> 1,102,358 iterations, 110,203 per second > > -- > www.tudorgirba.com > www.feenk.com > > "There are no old things, there are only old ways of looking at them." > > > > > |
In reply to this post by Tudor Girba-2
NO
> On 20 Dec 2015, at 14:32, Tudor Girba <[hidden email]> wrote: > > Hi, > >> On Dec 20, 2015, at 2:30 PM, Max Leske <[hidden email]> wrote: >> >> >>> On 20 Dec 2015, at 14:10, Tudor Girba <[hidden email]> wrote: >>> >>> Hi, >>> >>> Could we not have sum, but sumNumbers instead? So, we would end up with: >>> >>> sum:ifEmpty: >>> sum: (with error) >>> sumNumbers (without error) >>> >>> From the outside, #sum: looks like it should parameterize #sum, but the implementation is actually different. So, given that in this implementation #sum is not a special case of #sum: the two should be named differently to reflect that difference. Hence my proposal is to keep #sumNumbers instead of #sum. >> >> I could live with that. We would sacrifice the beautiful selector #sum for the more intention revealing #sumNumbers. I think that makes sense. >> >> Concerning the #min and #max methods that means we’d end up with e.g. #minNumbers, #min: and #min:ifEmpty: etc. > > Yes. > > Doru > > >> >>> >>> Cheers, >>> Doru >>> >>> >>>> On Dec 20, 2015, at 1:47 PM, Max Leske <[hidden email]> wrote: >>>> >>>>> >>>>> On 20 Dec 2015, at 13:43, Gabriel Cotelli <[hidden email]> wrote: >>>>> >>>>> Max, >>>>> >>>>> sum: aBlock ifEmpty: emptyBlock needs to obtain the sample evaluating the block. >>>>> >>>>> sum: aBlock ifEmpty: emptyBlock >>>>> | sum sample | >>>>> self isEmpty ifTrue: [ ^ emptyBlock value ]. >>>>> sample := aBlock value: self anyOne. >>>>> sum := self >>>>> inject: sample >>>>> into: [ :accum :each | accum + (aBlock value: each) ]. >>>>> ^ sum - sample >>>> >>>> >>>> Thanks! Missed that. >>>> >>>>> >>>>> On Sun, Dec 20, 2015 at 8:59 AM, Max Leske <[hidden email]> wrote: >>>>> I would like to wrap up this discussion. >>>>> >>>>> >>>>>> On 05 Dec 2015, at 18:14, stepharo <[hidden email]> wrote: >>>>>> >>>>>> So what is the conclusion? >>>>>> I like the idea of Esteban M to have iterator because it moves some behavior out of core classes. >>>>>> >>>>>> [[[ >>>>>> >>>>>> aCollection arithmetic sum: [...] or.... aCollection >>>>>> arithmetic avg. >>>>>> >>>>>> ]]] >>>>>> >>>>> >>>>> While I think that iterators are an intriguing idea I also believe that they are beyond the scope of this issue. If anybody wants to follow up on iterators (or unit types for that matter) please start a new thread / issue. >>>>> >>>>> >>>>> I propose to use Sven’s version for #sum:ifEmpty:. The result would be these three methods: >>>>> >>>>> sum >>>>> ^ self >>>>> sum: [ :each | each ] >>>>> ifEmpty: [ 0 ] >>>>> >>>>> sum: aBlock >>>>> ^ self >>>>> sum: aBlock >>>>> ifEmpty: [ self errorEmptyCollection ] >>>>> >>>>> sum: aBlock ifEmpty: emptyBlock >>>>> | sum sample | >>>>> self isEmpty ifTrue: [ ^ emptyBlock value ]. >>>>> sample := self anyOne. >>>>> sum := self >>>>> inject: sample >>>>> into: [ :accum :each | accum + (aBlock value: each) ]. >>>>> ^ sum - sample >>>>> >>>>> >>>>> I’ve attached a couple of benchmark results below. To me they show that >>>>> 1. the new implementation is maybe a tiny bit slower but insignificantly so (if you’re going for performance you’ll probably write your own optimised version anyway) >>>>> 2. there is no need to duplicate the code (like #sum and #sum: currently do). It’s perfectly fine to delegate to #sum:ifEmpty: >>>>> >>>>> >>>>> >>>>> In addition to the above changes I would like to remove #detectSum: (-> #sum:) and #sumNumbers (-> #sum). >>>>> >>>>> >>>>> Note that once we agree on changing this API, we will need to also change #detectMin:, #detectMax:, #min, #max as well as all overrides (e.g. RunArray, Interval) of these and of #sum et. al. to stay consistent. The changes would of course be in line with this change, such that every operation has a unary selector with a sensible default, one that takes a block and throws an error for empty collections and a third that takes a block for the iteration and one for the empty case. >>>>> >>>>> >>>>> Please cast your vote for these changes: >>>>> >>>>> 1. Do you agree to changing #sum and #sum: in the suggested way? >>>>> >>>>> 2. Do you agree to the removal of #detectSum:? >>>>> >>>>> 3. Do you agree to the removal of #sumNumbers? >>>>> >>>>> 4. Do you agree that the #max and #min selectors also need to be adapted? >>>>> >>>>> >>>>> >>>>> Thanks for you help. >>>>> >>>>> Cheers, >>>>> Max >>>>> >>>>> >>>>> >>>>> >>>>> >>>>> Benchmarks >>>>> ============ >>>>> (Note that these aren’t very good benchmarks. There’s quite some variation on each run.) >>>>> >>>>> >>>>> Machine: >>>>> MacBook Pro (15-inch, Early 2011) >>>>> CPU: 2.2 GHz Intel Core i7 >>>>> Memory: 8 GB 1333 MHz DDR3 >>>>> Disk: APPLE SSD TS512C (500 GB) >>>>> >>>>> >>>>> Benchmarks of the current versions: >>>>> >>>>> [ (1 to: 1000000) asArray sum ] benchFor: 10 seconds. >>>>> 75 iterations, 7.470 per second >>>>> >>>>> [ (1 to: 1000000) asArray sum: [ :e | e ] ] benchFor: 10 seconds. >>>>> 72 iterations, 7.128 per second >>>>> >>>>> >>>>> [ (1 to: 100) asArray sum ] benchFor: 10 seconds. >>>>> 1,189,477 iterations, 118,912 per second >>>>> >>>>> >>>>> [ (1 to: 100) asArray sum: [ :e | e ] ] benchFor: 10 seconds. >>>>> 1,171,467 iterations, 117,112 per second >>>>> >>>>> >>>>> >>>>> Benchmarks of the new versions: >>>>> >>>>> [ (1 to: 1000000) asArray sum ] benchFor: 10 seconds. >>>>> 73 iterations, 7.244 per second >>>>> >>>>> [ (1 to: 1000000) asArray sum: [ :e | e ] ] benchFor: 10 seconds. >>>>> 75 iterations, 7.480 per second >>>>> >>>>> [ (1 to: 1000000) asArray sum: [ :e | e ] ifEmpty: [ 0 ] ] benchFor: 10 seconds. >>>>> 72 iterations, 7.141 per second >>>>> >>>>> >>>>> [ (1 to: 100) asArray sum ] benchFor: 10 seconds. >>>>> 1,115,827 iterations, 111,560 per second >>>>> >>>>> [ (1 to: 100) asArray sum: [ :e | e ] ] benchFor: 10 seconds. >>>>> 1,154,595 iterations, 115,425 per second >>>>> >>>>> [ (1 to: 100) asArray sum: [ :e | e ] ifEmpty: [ 0 ] ] benchFor: 10 seconds. >>>>> 1,102,358 iterations, 110,203 per second >>> >>> -- >>> www.tudorgirba.com >>> www.feenk.com >>> >>> "There are no old things, there are only old ways of looking at them." >>> >>> >>> >>> >>> >> >> > > -- > www.tudorgirba.com > www.feenk.com > > "If you can't say why something is relevant, > it probably isn't." |
Hi,
I am not sure I understand the meaning of NO in the context of the previous message. Is the NO related to the sumNumbers, or to the min, max? Cheers, Doru > On Dec 20, 2015, at 2:43 PM, Sven Van Caekenberghe <[hidden email]> wrote: > > NO > >> On 20 Dec 2015, at 14:32, Tudor Girba <[hidden email]> wrote: >> >> Hi, >> >>> On Dec 20, 2015, at 2:30 PM, Max Leske <[hidden email]> wrote: >>> >>> >>>> On 20 Dec 2015, at 14:10, Tudor Girba <[hidden email]> wrote: >>>> >>>> Hi, >>>> >>>> Could we not have sum, but sumNumbers instead? So, we would end up with: >>>> >>>> sum:ifEmpty: >>>> sum: (with error) >>>> sumNumbers (without error) >>>> >>>> From the outside, #sum: looks like it should parameterize #sum, but the implementation is actually different. So, given that in this implementation #sum is not a special case of #sum: the two should be named differently to reflect that difference. Hence my proposal is to keep #sumNumbers instead of #sum. >>> >>> I could live with that. We would sacrifice the beautiful selector #sum for the more intention revealing #sumNumbers. I think that makes sense. >>> >>> Concerning the #min and #max methods that means we’d end up with e.g. #minNumbers, #min: and #min:ifEmpty: etc. >> >> Yes. >> >> Doru >> >> >>> >>>> >>>> Cheers, >>>> Doru >>>> >>>> >>>>> On Dec 20, 2015, at 1:47 PM, Max Leske <[hidden email]> wrote: >>>>> >>>>>> >>>>>> On 20 Dec 2015, at 13:43, Gabriel Cotelli <[hidden email]> wrote: >>>>>> >>>>>> Max, >>>>>> >>>>>> sum: aBlock ifEmpty: emptyBlock needs to obtain the sample evaluating the block. >>>>>> >>>>>> sum: aBlock ifEmpty: emptyBlock >>>>>> | sum sample | >>>>>> self isEmpty ifTrue: [ ^ emptyBlock value ]. >>>>>> sample := aBlock value: self anyOne. >>>>>> sum := self >>>>>> inject: sample >>>>>> into: [ :accum :each | accum + (aBlock value: each) ]. >>>>>> ^ sum - sample >>>>> >>>>> >>>>> Thanks! Missed that. >>>>> >>>>>> >>>>>> On Sun, Dec 20, 2015 at 8:59 AM, Max Leske <[hidden email]> wrote: >>>>>> I would like to wrap up this discussion. >>>>>> >>>>>> >>>>>>> On 05 Dec 2015, at 18:14, stepharo <[hidden email]> wrote: >>>>>>> >>>>>>> So what is the conclusion? >>>>>>> I like the idea of Esteban M to have iterator because it moves some behavior out of core classes. >>>>>>> >>>>>>> [[[ >>>>>>> >>>>>>> aCollection arithmetic sum: [...] or.... aCollection >>>>>>> arithmetic avg. >>>>>>> >>>>>>> ]]] >>>>>>> >>>>>> >>>>>> While I think that iterators are an intriguing idea I also believe that they are beyond the scope of this issue. If anybody wants to follow up on iterators (or unit types for that matter) please start a new thread / issue. >>>>>> >>>>>> >>>>>> I propose to use Sven’s version for #sum:ifEmpty:. The result would be these three methods: >>>>>> >>>>>> sum >>>>>> ^ self >>>>>> sum: [ :each | each ] >>>>>> ifEmpty: [ 0 ] >>>>>> >>>>>> sum: aBlock >>>>>> ^ self >>>>>> sum: aBlock >>>>>> ifEmpty: [ self errorEmptyCollection ] >>>>>> >>>>>> sum: aBlock ifEmpty: emptyBlock >>>>>> | sum sample | >>>>>> self isEmpty ifTrue: [ ^ emptyBlock value ]. >>>>>> sample := self anyOne. >>>>>> sum := self >>>>>> inject: sample >>>>>> into: [ :accum :each | accum + (aBlock value: each) ]. >>>>>> ^ sum - sample >>>>>> >>>>>> >>>>>> I’ve attached a couple of benchmark results below. To me they show that >>>>>> 1. the new implementation is maybe a tiny bit slower but insignificantly so (if you’re going for performance you’ll probably write your own optimised version anyway) >>>>>> 2. there is no need to duplicate the code (like #sum and #sum: currently do). It’s perfectly fine to delegate to #sum:ifEmpty: >>>>>> >>>>>> >>>>>> >>>>>> In addition to the above changes I would like to remove #detectSum: (-> #sum:) and #sumNumbers (-> #sum). >>>>>> >>>>>> >>>>>> Note that once we agree on changing this API, we will need to also change #detectMin:, #detectMax:, #min, #max as well as all overrides (e.g. RunArray, Interval) of these and of #sum et. al. to stay consistent. The changes would of course be in line with this change, such that every operation has a unary selector with a sensible default, one that takes a block and throws an error for empty collections and a third that takes a block for the iteration and one for the empty case. >>>>>> >>>>>> >>>>>> Please cast your vote for these changes: >>>>>> >>>>>> 1. Do you agree to changing #sum and #sum: in the suggested way? >>>>>> >>>>>> 2. Do you agree to the removal of #detectSum:? >>>>>> >>>>>> 3. Do you agree to the removal of #sumNumbers? >>>>>> >>>>>> 4. Do you agree that the #max and #min selectors also need to be adapted? >>>>>> >>>>>> >>>>>> >>>>>> Thanks for you help. >>>>>> >>>>>> Cheers, >>>>>> Max >>>>>> >>>>>> >>>>>> >>>>>> >>>>>> >>>>>> Benchmarks >>>>>> ============ >>>>>> (Note that these aren’t very good benchmarks. There’s quite some variation on each run.) >>>>>> >>>>>> >>>>>> Machine: >>>>>> MacBook Pro (15-inch, Early 2011) >>>>>> CPU: 2.2 GHz Intel Core i7 >>>>>> Memory: 8 GB 1333 MHz DDR3 >>>>>> Disk: APPLE SSD TS512C (500 GB) >>>>>> >>>>>> >>>>>> Benchmarks of the current versions: >>>>>> >>>>>> [ (1 to: 1000000) asArray sum ] benchFor: 10 seconds. >>>>>> 75 iterations, 7.470 per second >>>>>> >>>>>> [ (1 to: 1000000) asArray sum: [ :e | e ] ] benchFor: 10 seconds. >>>>>> 72 iterations, 7.128 per second >>>>>> >>>>>> >>>>>> [ (1 to: 100) asArray sum ] benchFor: 10 seconds. >>>>>> 1,189,477 iterations, 118,912 per second >>>>>> >>>>>> >>>>>> [ (1 to: 100) asArray sum: [ :e | e ] ] benchFor: 10 seconds. >>>>>> 1,171,467 iterations, 117,112 per second >>>>>> >>>>>> >>>>>> >>>>>> Benchmarks of the new versions: >>>>>> >>>>>> [ (1 to: 1000000) asArray sum ] benchFor: 10 seconds. >>>>>> 73 iterations, 7.244 per second >>>>>> >>>>>> [ (1 to: 1000000) asArray sum: [ :e | e ] ] benchFor: 10 seconds. >>>>>> 75 iterations, 7.480 per second >>>>>> >>>>>> [ (1 to: 1000000) asArray sum: [ :e | e ] ifEmpty: [ 0 ] ] benchFor: 10 seconds. >>>>>> 72 iterations, 7.141 per second >>>>>> >>>>>> >>>>>> [ (1 to: 100) asArray sum ] benchFor: 10 seconds. >>>>>> 1,115,827 iterations, 111,560 per second >>>>>> >>>>>> [ (1 to: 100) asArray sum: [ :e | e ] ] benchFor: 10 seconds. >>>>>> 1,154,595 iterations, 115,425 per second >>>>>> >>>>>> [ (1 to: 100) asArray sum: [ :e | e ] ifEmpty: [ 0 ] ] benchFor: 10 seconds. >>>>>> 1,102,358 iterations, 110,203 per second >>>> >>>> -- >>>> www.tudorgirba.com >>>> www.feenk.com >>>> >>>> "There are no old things, there are only old ways of looking at them." >>>> >>>> >>>> >>>> >>>> >>> >>> >> >> -- >> www.tudorgirba.com >> www.feenk.com >> >> "If you can't say why something is relevant, >> it probably isn't." > > -- www.tudorgirba.com www.feenk.com "Beauty is where we see it." |
In reply to this post by Sven Van Caekenberghe-2
Hi,
It’s clear that choices we would make would not be the same :). So, let’s drop past discussions and stay with the current situation. Do you agree with the observation that in the proposal of Max #sum and #sum: would not share the same meaning? If yes, do you agree that it would be misleading from the outside? I would be fine with either answer. I would just want to understand. Cheers, Doru > On Dec 20, 2015, at 2:43 PM, Sven Van Caekenberghe <[hidden email]> wrote: > > Doru, > > For me this whole discussion started because you (the standpoint that you take) hijacked the best selector (#sum) for a use case that is much less common than adding a collection of numbers which should give 0 when empty (you hijack it by not wanting to return 0, which I totally understand, but doing so you redefine the meaning/semantics). > > Max's point is to make everything more consistent and remove some API. I support that too. > > Now, I like Max's proposal. > > But, you know, my conclusion when the thread ended was that it might be better to throw all these selectors away, since #inject:into: covers most use cases at least as well and at least as clear. > > Sven > >> On 20 Dec 2015, at 14:10, Tudor Girba <[hidden email]> wrote: >> >> Hi, >> >> Could we not have sum, but sumNumbers instead? So, we would end up with: >> >> sum:ifEmpty: >> sum: (with error) >> sumNumbers (without error) >> >> From the outside, #sum: looks like it should parameterize #sum, but the implementation is actually different. So, given that in this implementation #sum is not a special case of #sum: the two should be named differently to reflect that difference. Hence my proposal is to keep #sumNumbers instead of #sum. >> >> Cheers, >> Doru >> >> >>> On Dec 20, 2015, at 1:47 PM, Max Leske <[hidden email]> wrote: >>> >>>> >>>> On 20 Dec 2015, at 13:43, Gabriel Cotelli <[hidden email]> wrote: >>>> >>>> Max, >>>> >>>> sum: aBlock ifEmpty: emptyBlock needs to obtain the sample evaluating the block. >>>> >>>> sum: aBlock ifEmpty: emptyBlock >>>> | sum sample | >>>> self isEmpty ifTrue: [ ^ emptyBlock value ]. >>>> sample := aBlock value: self anyOne. >>>> sum := self >>>> inject: sample >>>> into: [ :accum :each | accum + (aBlock value: each) ]. >>>> ^ sum - sample >>> >>> >>> Thanks! Missed that. >>> >>>> >>>> On Sun, Dec 20, 2015 at 8:59 AM, Max Leske <[hidden email]> wrote: >>>> I would like to wrap up this discussion. >>>> >>>> >>>>> On 05 Dec 2015, at 18:14, stepharo <[hidden email]> wrote: >>>>> >>>>> So what is the conclusion? >>>>> I like the idea of Esteban M to have iterator because it moves some behavior out of core classes. >>>>> >>>>> [[[ >>>>> >>>>> aCollection arithmetic sum: [...] or.... aCollection >>>>> arithmetic avg. >>>>> >>>>> ]]] >>>>> >>>> >>>> While I think that iterators are an intriguing idea I also believe that they are beyond the scope of this issue. If anybody wants to follow up on iterators (or unit types for that matter) please start a new thread / issue. >>>> >>>> >>>> I propose to use Sven’s version for #sum:ifEmpty:. The result would be these three methods: >>>> >>>> sum >>>> ^ self >>>> sum: [ :each | each ] >>>> ifEmpty: [ 0 ] >>>> >>>> sum: aBlock >>>> ^ self >>>> sum: aBlock >>>> ifEmpty: [ self errorEmptyCollection ] >>>> >>>> sum: aBlock ifEmpty: emptyBlock >>>> | sum sample | >>>> self isEmpty ifTrue: [ ^ emptyBlock value ]. >>>> sample := self anyOne. >>>> sum := self >>>> inject: sample >>>> into: [ :accum :each | accum + (aBlock value: each) ]. >>>> ^ sum - sample >>>> >>>> >>>> I’ve attached a couple of benchmark results below. To me they show that >>>> 1. the new implementation is maybe a tiny bit slower but insignificantly so (if you’re going for performance you’ll probably write your own optimised version anyway) >>>> 2. there is no need to duplicate the code (like #sum and #sum: currently do). It’s perfectly fine to delegate to #sum:ifEmpty: >>>> >>>> >>>> >>>> In addition to the above changes I would like to remove #detectSum: (-> #sum:) and #sumNumbers (-> #sum). >>>> >>>> >>>> Note that once we agree on changing this API, we will need to also change #detectMin:, #detectMax:, #min, #max as well as all overrides (e.g. RunArray, Interval) of these and of #sum et. al. to stay consistent. The changes would of course be in line with this change, such that every operation has a unary selector with a sensible default, one that takes a block and throws an error for empty collections and a third that takes a block for the iteration and one for the empty case. >>>> >>>> >>>> Please cast your vote for these changes: >>>> >>>> 1. Do you agree to changing #sum and #sum: in the suggested way? >>>> >>>> 2. Do you agree to the removal of #detectSum:? >>>> >>>> 3. Do you agree to the removal of #sumNumbers? >>>> >>>> 4. Do you agree that the #max and #min selectors also need to be adapted? >>>> >>>> >>>> >>>> Thanks for you help. >>>> >>>> Cheers, >>>> Max >>>> >>>> >>>> >>>> >>>> >>>> Benchmarks >>>> ============ >>>> (Note that these aren’t very good benchmarks. There’s quite some variation on each run.) >>>> >>>> >>>> Machine: >>>> MacBook Pro (15-inch, Early 2011) >>>> CPU: 2.2 GHz Intel Core i7 >>>> Memory: 8 GB 1333 MHz DDR3 >>>> Disk: APPLE SSD TS512C (500 GB) >>>> >>>> >>>> Benchmarks of the current versions: >>>> >>>> [ (1 to: 1000000) asArray sum ] benchFor: 10 seconds. >>>> 75 iterations, 7.470 per second >>>> >>>> [ (1 to: 1000000) asArray sum: [ :e | e ] ] benchFor: 10 seconds. >>>> 72 iterations, 7.128 per second >>>> >>>> >>>> [ (1 to: 100) asArray sum ] benchFor: 10 seconds. >>>> 1,189,477 iterations, 118,912 per second >>>> >>>> >>>> [ (1 to: 100) asArray sum: [ :e | e ] ] benchFor: 10 seconds. >>>> 1,171,467 iterations, 117,112 per second >>>> >>>> >>>> >>>> Benchmarks of the new versions: >>>> >>>> [ (1 to: 1000000) asArray sum ] benchFor: 10 seconds. >>>> 73 iterations, 7.244 per second >>>> >>>> [ (1 to: 1000000) asArray sum: [ :e | e ] ] benchFor: 10 seconds. >>>> 75 iterations, 7.480 per second >>>> >>>> [ (1 to: 1000000) asArray sum: [ :e | e ] ifEmpty: [ 0 ] ] benchFor: 10 seconds. >>>> 72 iterations, 7.141 per second >>>> >>>> >>>> [ (1 to: 100) asArray sum ] benchFor: 10 seconds. >>>> 1,115,827 iterations, 111,560 per second >>>> >>>> [ (1 to: 100) asArray sum: [ :e | e ] ] benchFor: 10 seconds. >>>> 1,154,595 iterations, 115,425 per second >>>> >>>> [ (1 to: 100) asArray sum: [ :e | e ] ifEmpty: [ 0 ] ] benchFor: 10 seconds. >>>> 1,102,358 iterations, 110,203 per second >> >> -- >> www.tudorgirba.com >> www.feenk.com >> >> "There are no old things, there are only old ways of looking at them." >> >> >> >> >> > > -- www.tudorgirba.com www.feenk.com "It's not how it is, it is how we see it." |
In reply to this post by Tudor Girba-2
No means I don't want to start adding Numbers to beautiful unary selectors. I don't understand why you don't understand that point about beauty and simplicity.
> On 20 Dec 2015, at 14:54, Tudor Girba <[hidden email]> wrote: > > Hi, > > I am not sure I understand the meaning of NO in the context of the previous message. > > Is the NO related to the sumNumbers, or to the min, max? > > Cheers, > Doru > > >> On Dec 20, 2015, at 2:43 PM, Sven Van Caekenberghe <[hidden email]> wrote: >> >> NO >> >>> On 20 Dec 2015, at 14:32, Tudor Girba <[hidden email]> wrote: >>> >>> Hi, >>> >>>> On Dec 20, 2015, at 2:30 PM, Max Leske <[hidden email]> wrote: >>>> >>>> >>>>> On 20 Dec 2015, at 14:10, Tudor Girba <[hidden email]> wrote: >>>>> >>>>> Hi, >>>>> >>>>> Could we not have sum, but sumNumbers instead? So, we would end up with: >>>>> >>>>> sum:ifEmpty: >>>>> sum: (with error) >>>>> sumNumbers (without error) >>>>> >>>>> From the outside, #sum: looks like it should parameterize #sum, but the implementation is actually different. So, given that in this implementation #sum is not a special case of #sum: the two should be named differently to reflect that difference. Hence my proposal is to keep #sumNumbers instead of #sum. >>>> >>>> I could live with that. We would sacrifice the beautiful selector #sum for the more intention revealing #sumNumbers. I think that makes sense. >>>> >>>> Concerning the #min and #max methods that means we’d end up with e.g. #minNumbers, #min: and #min:ifEmpty: etc. >>> >>> Yes. >>> >>> Doru >>> >>> >>>> >>>>> >>>>> Cheers, >>>>> Doru >>>>> >>>>> >>>>>> On Dec 20, 2015, at 1:47 PM, Max Leske <[hidden email]> wrote: >>>>>> >>>>>>> >>>>>>> On 20 Dec 2015, at 13:43, Gabriel Cotelli <[hidden email]> wrote: >>>>>>> >>>>>>> Max, >>>>>>> >>>>>>> sum: aBlock ifEmpty: emptyBlock needs to obtain the sample evaluating the block. >>>>>>> >>>>>>> sum: aBlock ifEmpty: emptyBlock >>>>>>> | sum sample | >>>>>>> self isEmpty ifTrue: [ ^ emptyBlock value ]. >>>>>>> sample := aBlock value: self anyOne. >>>>>>> sum := self >>>>>>> inject: sample >>>>>>> into: [ :accum :each | accum + (aBlock value: each) ]. >>>>>>> ^ sum - sample >>>>>> >>>>>> >>>>>> Thanks! Missed that. >>>>>> >>>>>>> >>>>>>> On Sun, Dec 20, 2015 at 8:59 AM, Max Leske <[hidden email]> wrote: >>>>>>> I would like to wrap up this discussion. >>>>>>> >>>>>>> >>>>>>>> On 05 Dec 2015, at 18:14, stepharo <[hidden email]> wrote: >>>>>>>> >>>>>>>> So what is the conclusion? >>>>>>>> I like the idea of Esteban M to have iterator because it moves some behavior out of core classes. >>>>>>>> >>>>>>>> [[[ >>>>>>>> >>>>>>>> aCollection arithmetic sum: [...] or.... aCollection >>>>>>>> arithmetic avg. >>>>>>>> >>>>>>>> ]]] >>>>>>>> >>>>>>> >>>>>>> While I think that iterators are an intriguing idea I also believe that they are beyond the scope of this issue. If anybody wants to follow up on iterators (or unit types for that matter) please start a new thread / issue. >>>>>>> >>>>>>> >>>>>>> I propose to use Sven’s version for #sum:ifEmpty:. The result would be these three methods: >>>>>>> >>>>>>> sum >>>>>>> ^ self >>>>>>> sum: [ :each | each ] >>>>>>> ifEmpty: [ 0 ] >>>>>>> >>>>>>> sum: aBlock >>>>>>> ^ self >>>>>>> sum: aBlock >>>>>>> ifEmpty: [ self errorEmptyCollection ] >>>>>>> >>>>>>> sum: aBlock ifEmpty: emptyBlock >>>>>>> | sum sample | >>>>>>> self isEmpty ifTrue: [ ^ emptyBlock value ]. >>>>>>> sample := self anyOne. >>>>>>> sum := self >>>>>>> inject: sample >>>>>>> into: [ :accum :each | accum + (aBlock value: each) ]. >>>>>>> ^ sum - sample >>>>>>> >>>>>>> >>>>>>> I’ve attached a couple of benchmark results below. To me they show that >>>>>>> 1. the new implementation is maybe a tiny bit slower but insignificantly so (if you’re going for performance you’ll probably write your own optimised version anyway) >>>>>>> 2. there is no need to duplicate the code (like #sum and #sum: currently do). It’s perfectly fine to delegate to #sum:ifEmpty: >>>>>>> >>>>>>> >>>>>>> >>>>>>> In addition to the above changes I would like to remove #detectSum: (-> #sum:) and #sumNumbers (-> #sum). >>>>>>> >>>>>>> >>>>>>> Note that once we agree on changing this API, we will need to also change #detectMin:, #detectMax:, #min, #max as well as all overrides (e.g. RunArray, Interval) of these and of #sum et. al. to stay consistent. The changes would of course be in line with this change, such that every operation has a unary selector with a sensible default, one that takes a block and throws an error for empty collections and a third that takes a block for the iteration and one for the empty case. >>>>>>> >>>>>>> >>>>>>> Please cast your vote for these changes: >>>>>>> >>>>>>> 1. Do you agree to changing #sum and #sum: in the suggested way? >>>>>>> >>>>>>> 2. Do you agree to the removal of #detectSum:? >>>>>>> >>>>>>> 3. Do you agree to the removal of #sumNumbers? >>>>>>> >>>>>>> 4. Do you agree that the #max and #min selectors also need to be adapted? >>>>>>> >>>>>>> >>>>>>> >>>>>>> Thanks for you help. >>>>>>> >>>>>>> Cheers, >>>>>>> Max >>>>>>> >>>>>>> >>>>>>> >>>>>>> >>>>>>> >>>>>>> Benchmarks >>>>>>> ============ >>>>>>> (Note that these aren’t very good benchmarks. There’s quite some variation on each run.) >>>>>>> >>>>>>> >>>>>>> Machine: >>>>>>> MacBook Pro (15-inch, Early 2011) >>>>>>> CPU: 2.2 GHz Intel Core i7 >>>>>>> Memory: 8 GB 1333 MHz DDR3 >>>>>>> Disk: APPLE SSD TS512C (500 GB) >>>>>>> >>>>>>> >>>>>>> Benchmarks of the current versions: >>>>>>> >>>>>>> [ (1 to: 1000000) asArray sum ] benchFor: 10 seconds. >>>>>>> 75 iterations, 7.470 per second >>>>>>> >>>>>>> [ (1 to: 1000000) asArray sum: [ :e | e ] ] benchFor: 10 seconds. >>>>>>> 72 iterations, 7.128 per second >>>>>>> >>>>>>> >>>>>>> [ (1 to: 100) asArray sum ] benchFor: 10 seconds. >>>>>>> 1,189,477 iterations, 118,912 per second >>>>>>> >>>>>>> >>>>>>> [ (1 to: 100) asArray sum: [ :e | e ] ] benchFor: 10 seconds. >>>>>>> 1,171,467 iterations, 117,112 per second >>>>>>> >>>>>>> >>>>>>> >>>>>>> Benchmarks of the new versions: >>>>>>> >>>>>>> [ (1 to: 1000000) asArray sum ] benchFor: 10 seconds. >>>>>>> 73 iterations, 7.244 per second >>>>>>> >>>>>>> [ (1 to: 1000000) asArray sum: [ :e | e ] ] benchFor: 10 seconds. >>>>>>> 75 iterations, 7.480 per second >>>>>>> >>>>>>> [ (1 to: 1000000) asArray sum: [ :e | e ] ifEmpty: [ 0 ] ] benchFor: 10 seconds. >>>>>>> 72 iterations, 7.141 per second >>>>>>> >>>>>>> >>>>>>> [ (1 to: 100) asArray sum ] benchFor: 10 seconds. >>>>>>> 1,115,827 iterations, 111,560 per second >>>>>>> >>>>>>> [ (1 to: 100) asArray sum: [ :e | e ] ] benchFor: 10 seconds. >>>>>>> 1,154,595 iterations, 115,425 per second >>>>>>> >>>>>>> [ (1 to: 100) asArray sum: [ :e | e ] ifEmpty: [ 0 ] ] benchFor: 10 seconds. >>>>>>> 1,102,358 iterations, 110,203 per second >>>>> >>>>> -- >>>>> www.tudorgirba.com >>>>> www.feenk.com >>>>> >>>>> "There are no old things, there are only old ways of looking at them." >>>>> >>>>> >>>>> >>>>> >>>>> >>>> >>>> >>> >>> -- >>> www.tudorgirba.com >>> www.feenk.com >>> >>> "If you can't say why something is relevant, >>> it probably isn't." >> >> > > -- > www.tudorgirba.com > www.feenk.com > > "Beauty is where we see it." > > > > > |
In reply to this post by Tudor Girba-2
> On 20 Dec 2015, at 14:57, Tudor Girba <[hidden email]> wrote: > > Hi, > > It’s clear that choices we would make would not be the same :). So, let’s drop past discussions and stay with the current situation. Do you agree with the observation that in the proposal of Max #sum and #sum: would not share the same meaning? If yes, do you agree that it would be misleading from the outside? The overal meaning is the same, IMO, summing a number of things (most often numbers) using #+. The processing block just adds functionality. The behaviour in the case of an empty collection is different yes. I want 0, why, because of https://en.wikipedia.org/wiki/Empty_sum This is about optimisation for the common case. VW had no #sum, I think because of all the points raised in this discussion (you can't always expect numbers and it is not clear what to do with empty collections). Check out the senders of #sum and #sum: in a 50 image. > I would be fine with either answer. I would just want to understand. > > Cheers, > Doru > > >> On Dec 20, 2015, at 2:43 PM, Sven Van Caekenberghe <[hidden email]> wrote: >> >> Doru, >> >> For me this whole discussion started because you (the standpoint that you take) hijacked the best selector (#sum) for a use case that is much less common than adding a collection of numbers which should give 0 when empty (you hijack it by not wanting to return 0, which I totally understand, but doing so you redefine the meaning/semantics). >> >> Max's point is to make everything more consistent and remove some API. I support that too. >> >> Now, I like Max's proposal. >> >> But, you know, my conclusion when the thread ended was that it might be better to throw all these selectors away, since #inject:into: covers most use cases at least as well and at least as clear. >> >> Sven >> >>> On 20 Dec 2015, at 14:10, Tudor Girba <[hidden email]> wrote: >>> >>> Hi, >>> >>> Could we not have sum, but sumNumbers instead? So, we would end up with: >>> >>> sum:ifEmpty: >>> sum: (with error) >>> sumNumbers (without error) >>> >>> From the outside, #sum: looks like it should parameterize #sum, but the implementation is actually different. So, given that in this implementation #sum is not a special case of #sum: the two should be named differently to reflect that difference. Hence my proposal is to keep #sumNumbers instead of #sum. >>> >>> Cheers, >>> Doru >>> >>> >>>> On Dec 20, 2015, at 1:47 PM, Max Leske <[hidden email]> wrote: >>>> >>>>> >>>>> On 20 Dec 2015, at 13:43, Gabriel Cotelli <[hidden email]> wrote: >>>>> >>>>> Max, >>>>> >>>>> sum: aBlock ifEmpty: emptyBlock needs to obtain the sample evaluating the block. >>>>> >>>>> sum: aBlock ifEmpty: emptyBlock >>>>> | sum sample | >>>>> self isEmpty ifTrue: [ ^ emptyBlock value ]. >>>>> sample := aBlock value: self anyOne. >>>>> sum := self >>>>> inject: sample >>>>> into: [ :accum :each | accum + (aBlock value: each) ]. >>>>> ^ sum - sample >>>> >>>> >>>> Thanks! Missed that. >>>> >>>>> >>>>> On Sun, Dec 20, 2015 at 8:59 AM, Max Leske <[hidden email]> wrote: >>>>> I would like to wrap up this discussion. >>>>> >>>>> >>>>>> On 05 Dec 2015, at 18:14, stepharo <[hidden email]> wrote: >>>>>> >>>>>> So what is the conclusion? >>>>>> I like the idea of Esteban M to have iterator because it moves some behavior out of core classes. >>>>>> >>>>>> [[[ >>>>>> >>>>>> aCollection arithmetic sum: [...] or.... aCollection >>>>>> arithmetic avg. >>>>>> >>>>>> ]]] >>>>>> >>>>> >>>>> While I think that iterators are an intriguing idea I also believe that they are beyond the scope of this issue. If anybody wants to follow up on iterators (or unit types for that matter) please start a new thread / issue. >>>>> >>>>> >>>>> I propose to use Sven’s version for #sum:ifEmpty:. The result would be these three methods: >>>>> >>>>> sum >>>>> ^ self >>>>> sum: [ :each | each ] >>>>> ifEmpty: [ 0 ] >>>>> >>>>> sum: aBlock >>>>> ^ self >>>>> sum: aBlock >>>>> ifEmpty: [ self errorEmptyCollection ] >>>>> >>>>> sum: aBlock ifEmpty: emptyBlock >>>>> | sum sample | >>>>> self isEmpty ifTrue: [ ^ emptyBlock value ]. >>>>> sample := self anyOne. >>>>> sum := self >>>>> inject: sample >>>>> into: [ :accum :each | accum + (aBlock value: each) ]. >>>>> ^ sum - sample >>>>> >>>>> >>>>> I’ve attached a couple of benchmark results below. To me they show that >>>>> 1. the new implementation is maybe a tiny bit slower but insignificantly so (if you’re going for performance you’ll probably write your own optimised version anyway) >>>>> 2. there is no need to duplicate the code (like #sum and #sum: currently do). It’s perfectly fine to delegate to #sum:ifEmpty: >>>>> >>>>> >>>>> >>>>> In addition to the above changes I would like to remove #detectSum: (-> #sum:) and #sumNumbers (-> #sum). >>>>> >>>>> >>>>> Note that once we agree on changing this API, we will need to also change #detectMin:, #detectMax:, #min, #max as well as all overrides (e.g. RunArray, Interval) of these and of #sum et. al. to stay consistent. The changes would of course be in line with this change, such that every operation has a unary selector with a sensible default, one that takes a block and throws an error for empty collections and a third that takes a block for the iteration and one for the empty case. >>>>> >>>>> >>>>> Please cast your vote for these changes: >>>>> >>>>> 1. Do you agree to changing #sum and #sum: in the suggested way? >>>>> >>>>> 2. Do you agree to the removal of #detectSum:? >>>>> >>>>> 3. Do you agree to the removal of #sumNumbers? >>>>> >>>>> 4. Do you agree that the #max and #min selectors also need to be adapted? >>>>> >>>>> >>>>> >>>>> Thanks for you help. >>>>> >>>>> Cheers, >>>>> Max >>>>> >>>>> >>>>> >>>>> >>>>> >>>>> Benchmarks >>>>> ============ >>>>> (Note that these aren’t very good benchmarks. There’s quite some variation on each run.) >>>>> >>>>> >>>>> Machine: >>>>> MacBook Pro (15-inch, Early 2011) >>>>> CPU: 2.2 GHz Intel Core i7 >>>>> Memory: 8 GB 1333 MHz DDR3 >>>>> Disk: APPLE SSD TS512C (500 GB) >>>>> >>>>> >>>>> Benchmarks of the current versions: >>>>> >>>>> [ (1 to: 1000000) asArray sum ] benchFor: 10 seconds. >>>>> 75 iterations, 7.470 per second >>>>> >>>>> [ (1 to: 1000000) asArray sum: [ :e | e ] ] benchFor: 10 seconds. >>>>> 72 iterations, 7.128 per second >>>>> >>>>> >>>>> [ (1 to: 100) asArray sum ] benchFor: 10 seconds. >>>>> 1,189,477 iterations, 118,912 per second >>>>> >>>>> >>>>> [ (1 to: 100) asArray sum: [ :e | e ] ] benchFor: 10 seconds. >>>>> 1,171,467 iterations, 117,112 per second >>>>> >>>>> >>>>> >>>>> Benchmarks of the new versions: >>>>> >>>>> [ (1 to: 1000000) asArray sum ] benchFor: 10 seconds. >>>>> 73 iterations, 7.244 per second >>>>> >>>>> [ (1 to: 1000000) asArray sum: [ :e | e ] ] benchFor: 10 seconds. >>>>> 75 iterations, 7.480 per second >>>>> >>>>> [ (1 to: 1000000) asArray sum: [ :e | e ] ifEmpty: [ 0 ] ] benchFor: 10 seconds. >>>>> 72 iterations, 7.141 per second >>>>> >>>>> >>>>> [ (1 to: 100) asArray sum ] benchFor: 10 seconds. >>>>> 1,115,827 iterations, 111,560 per second >>>>> >>>>> [ (1 to: 100) asArray sum: [ :e | e ] ] benchFor: 10 seconds. >>>>> 1,154,595 iterations, 115,425 per second >>>>> >>>>> [ (1 to: 100) asArray sum: [ :e | e ] ifEmpty: [ 0 ] ] benchFor: 10 seconds. >>>>> 1,102,358 iterations, 110,203 per second >>> >>> -- >>> www.tudorgirba.com >>> www.feenk.com >>> >>> "There are no old things, there are only old ways of looking at them." >>> >>> >>> >>> >>> >> >> > > -- > www.tudorgirba.com > www.feenk.com > > "It's not how it is, it is how we see it." > > |
Hi,
> On Dec 20, 2015, at 3:07 PM, Sven Van Caekenberghe <[hidden email]> wrote: > > >> On 20 Dec 2015, at 14:57, Tudor Girba <[hidden email]> wrote: >> >> Hi, >> >> It’s clear that choices we would make would not be the same :). So, let’s drop past discussions and stay with the current situation. Do you agree with the observation that in the proposal of Max #sum and #sum: would not share the same meaning? If yes, do you agree that it would be misleading from the outside? > > The overal meaning is the same, IMO, summing a number of things (most often numbers) using #+. The processing block just adds functionality. > > The behaviour in the case of an empty collection is different yes. I want 0, why, because of https://en.wikipedia.org/wiki/Empty_sum > > This is about optimisation for the common case. Fair enough. But, then why are you not equally picking on the fact that #sum: throws an error? :) We are really overusing a term for something we should not and I think in the process we are getting to a tradeoff that does not lead to simplicity. From my point of view this discussion is similar to having Object>>#name. It kind of makes common sense to ask an object for its name, only that in a few situations it is actually painful to have it there :) > VW had no #sum, I think because of all the points raised in this discussion (you can't always expect numbers and it is not clear what to do with empty collections). I would not guide our decisions based on what VW did or did not do (I could not resist :)). > Check out the senders of #sum and #sum: in a 50 image. Sure, but we are supposed to create a language that is used by others. In the base image, there is no problem with Object>>#name either, but it is still not a good thing :) So, why not remove #sum altogether then? Cheers, Doru >> I would be fine with either answer. I would just want to understand. >> >> Cheers, >> Doru >> >> >>> On Dec 20, 2015, at 2:43 PM, Sven Van Caekenberghe <[hidden email]> wrote: >>> >>> Doru, >>> >>> For me this whole discussion started because you (the standpoint that you take) hijacked the best selector (#sum) for a use case that is much less common than adding a collection of numbers which should give 0 when empty (you hijack it by not wanting to return 0, which I totally understand, but doing so you redefine the meaning/semantics). >>> >>> Max's point is to make everything more consistent and remove some API. I support that too. >>> >>> Now, I like Max's proposal. >>> >>> But, you know, my conclusion when the thread ended was that it might be better to throw all these selectors away, since #inject:into: covers most use cases at least as well and at least as clear. >>> >>> Sven >>> >>>> On 20 Dec 2015, at 14:10, Tudor Girba <[hidden email]> wrote: >>>> >>>> Hi, >>>> >>>> Could we not have sum, but sumNumbers instead? So, we would end up with: >>>> >>>> sum:ifEmpty: >>>> sum: (with error) >>>> sumNumbers (without error) >>>> >>>> From the outside, #sum: looks like it should parameterize #sum, but the implementation is actually different. So, given that in this implementation #sum is not a special case of #sum: the two should be named differently to reflect that difference. Hence my proposal is to keep #sumNumbers instead of #sum. >>>> >>>> Cheers, >>>> Doru >>>> >>>> >>>>> On Dec 20, 2015, at 1:47 PM, Max Leske <[hidden email]> wrote: >>>>> >>>>>> >>>>>> On 20 Dec 2015, at 13:43, Gabriel Cotelli <[hidden email]> wrote: >>>>>> >>>>>> Max, >>>>>> >>>>>> sum: aBlock ifEmpty: emptyBlock needs to obtain the sample evaluating the block. >>>>>> >>>>>> sum: aBlock ifEmpty: emptyBlock >>>>>> | sum sample | >>>>>> self isEmpty ifTrue: [ ^ emptyBlock value ]. >>>>>> sample := aBlock value: self anyOne. >>>>>> sum := self >>>>>> inject: sample >>>>>> into: [ :accum :each | accum + (aBlock value: each) ]. >>>>>> ^ sum - sample >>>>> >>>>> >>>>> Thanks! Missed that. >>>>> >>>>>> >>>>>> On Sun, Dec 20, 2015 at 8:59 AM, Max Leske <[hidden email]> wrote: >>>>>> I would like to wrap up this discussion. >>>>>> >>>>>> >>>>>>> On 05 Dec 2015, at 18:14, stepharo <[hidden email]> wrote: >>>>>>> >>>>>>> So what is the conclusion? >>>>>>> I like the idea of Esteban M to have iterator because it moves some behavior out of core classes. >>>>>>> >>>>>>> [[[ >>>>>>> >>>>>>> aCollection arithmetic sum: [...] or.... aCollection >>>>>>> arithmetic avg. >>>>>>> >>>>>>> ]]] >>>>>>> >>>>>> >>>>>> While I think that iterators are an intriguing idea I also believe that they are beyond the scope of this issue. If anybody wants to follow up on iterators (or unit types for that matter) please start a new thread / issue. >>>>>> >>>>>> >>>>>> I propose to use Sven’s version for #sum:ifEmpty:. The result would be these three methods: >>>>>> >>>>>> sum >>>>>> ^ self >>>>>> sum: [ :each | each ] >>>>>> ifEmpty: [ 0 ] >>>>>> >>>>>> sum: aBlock >>>>>> ^ self >>>>>> sum: aBlock >>>>>> ifEmpty: [ self errorEmptyCollection ] >>>>>> >>>>>> sum: aBlock ifEmpty: emptyBlock >>>>>> | sum sample | >>>>>> self isEmpty ifTrue: [ ^ emptyBlock value ]. >>>>>> sample := self anyOne. >>>>>> sum := self >>>>>> inject: sample >>>>>> into: [ :accum :each | accum + (aBlock value: each) ]. >>>>>> ^ sum - sample >>>>>> >>>>>> >>>>>> I’ve attached a couple of benchmark results below. To me they show that >>>>>> 1. the new implementation is maybe a tiny bit slower but insignificantly so (if you’re going for performance you’ll probably write your own optimised version anyway) >>>>>> 2. there is no need to duplicate the code (like #sum and #sum: currently do). It’s perfectly fine to delegate to #sum:ifEmpty: >>>>>> >>>>>> >>>>>> >>>>>> In addition to the above changes I would like to remove #detectSum: (-> #sum:) and #sumNumbers (-> #sum). >>>>>> >>>>>> >>>>>> Note that once we agree on changing this API, we will need to also change #detectMin:, #detectMax:, #min, #max as well as all overrides (e.g. RunArray, Interval) of these and of #sum et. al. to stay consistent. The changes would of course be in line with this change, such that every operation has a unary selector with a sensible default, one that takes a block and throws an error for empty collections and a third that takes a block for the iteration and one for the empty case. >>>>>> >>>>>> >>>>>> Please cast your vote for these changes: >>>>>> >>>>>> 1. Do you agree to changing #sum and #sum: in the suggested way? >>>>>> >>>>>> 2. Do you agree to the removal of #detectSum:? >>>>>> >>>>>> 3. Do you agree to the removal of #sumNumbers? >>>>>> >>>>>> 4. Do you agree that the #max and #min selectors also need to be adapted? >>>>>> >>>>>> >>>>>> >>>>>> Thanks for you help. >>>>>> >>>>>> Cheers, >>>>>> Max >>>>>> >>>>>> >>>>>> >>>>>> >>>>>> >>>>>> Benchmarks >>>>>> ============ >>>>>> (Note that these aren’t very good benchmarks. There’s quite some variation on each run.) >>>>>> >>>>>> >>>>>> Machine: >>>>>> MacBook Pro (15-inch, Early 2011) >>>>>> CPU: 2.2 GHz Intel Core i7 >>>>>> Memory: 8 GB 1333 MHz DDR3 >>>>>> Disk: APPLE SSD TS512C (500 GB) >>>>>> >>>>>> >>>>>> Benchmarks of the current versions: >>>>>> >>>>>> [ (1 to: 1000000) asArray sum ] benchFor: 10 seconds. >>>>>> 75 iterations, 7.470 per second >>>>>> >>>>>> [ (1 to: 1000000) asArray sum: [ :e | e ] ] benchFor: 10 seconds. >>>>>> 72 iterations, 7.128 per second >>>>>> >>>>>> >>>>>> [ (1 to: 100) asArray sum ] benchFor: 10 seconds. >>>>>> 1,189,477 iterations, 118,912 per second >>>>>> >>>>>> >>>>>> [ (1 to: 100) asArray sum: [ :e | e ] ] benchFor: 10 seconds. >>>>>> 1,171,467 iterations, 117,112 per second >>>>>> >>>>>> >>>>>> >>>>>> Benchmarks of the new versions: >>>>>> >>>>>> [ (1 to: 1000000) asArray sum ] benchFor: 10 seconds. >>>>>> 73 iterations, 7.244 per second >>>>>> >>>>>> [ (1 to: 1000000) asArray sum: [ :e | e ] ] benchFor: 10 seconds. >>>>>> 75 iterations, 7.480 per second >>>>>> >>>>>> [ (1 to: 1000000) asArray sum: [ :e | e ] ifEmpty: [ 0 ] ] benchFor: 10 seconds. >>>>>> 72 iterations, 7.141 per second >>>>>> >>>>>> >>>>>> [ (1 to: 100) asArray sum ] benchFor: 10 seconds. >>>>>> 1,115,827 iterations, 111,560 per second >>>>>> >>>>>> [ (1 to: 100) asArray sum: [ :e | e ] ] benchFor: 10 seconds. >>>>>> 1,154,595 iterations, 115,425 per second >>>>>> >>>>>> [ (1 to: 100) asArray sum: [ :e | e ] ifEmpty: [ 0 ] ] benchFor: 10 seconds. >>>>>> 1,102,358 iterations, 110,203 per second >>>> >>>> -- >>>> www.tudorgirba.com >>>> www.feenk.com >>>> >>>> "There are no old things, there are only old ways of looking at them." >>>> >>>> >>>> >>>> >>>> >>> >>> >> >> -- >> www.tudorgirba.com >> www.feenk.com >> >> "It's not how it is, it is how we see it." >> >> > > -- www.tudorgirba.com www.feenk.com "What we can governs what we wish." |
In reply to this post by Sven Van Caekenberghe-2
On Mon, Dec 21, 2015 at 12:43 AM, Sven Van Caekenberghe <[hidden email]> wrote:
> Doru, > > For me this whole discussion started because you (the standpoint that you take) hijacked the best selector (#sum) for a use case that is much less common than adding a collection of numbers which should give 0 when empty (you hijack it by not wanting to return 0, which I totally understand, but doing so you redefine the meaning/semantics). > > Max's point is to make everything more consistent and remove some API. I support that too. > > Now, I like Max's proposal. > > But, you know, my conclusion when the thread ended was that it might be better to throw all these selectors away, since #inject:into: covers most use cases at least as well and at least as clear. > > Sven > >> On 20 Dec 2015, at 14:10, Tudor Girba <[hidden email]> wrote: >> >> Hi, >> >> Could we not have sum, but sumNumbers instead? So, we would end up with: >> >> sum:ifEmpty: >> sum: (with error) >> sumNumbers (without error) >> >> From the outside, #sum: looks like it should parameterize #sum, but the implementation is actually different. So, given that in this implementation #sum is not a special case of #sum: the two should be named differently to reflect that difference. Hence my proposal is to keep #sumNumbers instead of #sum. I agree somewhat with Duro to avoid #sum and #sum: having different semantics, but I agree more with Sven about keeping #sum for numbers only and returning zero, so why not turn Doru's suggestion around... #sum (empty --> 0) #sumBy: (empty --> error) #sumBy: ifEmpty: (empty --> no error) alternatively could be #sumUsing: or #sumWith: or something similar. >> >> Cheers, >> Doru >> >> >>> On Dec 20, 2015, at 1:47 PM, Max Leske <[hidden email]> wrote: >>> >>>> >>>> On 20 Dec 2015, at 13:43, Gabriel Cotelli <[hidden email]> wrote: >>>> >>>> Max, >>>> >>>> sum: aBlock ifEmpty: emptyBlock needs to obtain the sample evaluating the block. >>>> >>>> sum: aBlock ifEmpty: emptyBlock >>>> | sum sample | >>>> self isEmpty ifTrue: [ ^ emptyBlock value ]. >>>> sample := aBlock value: self anyOne. >>>> sum := self >>>> inject: sample >>>> into: [ :accum :each | accum + (aBlock value: each) ]. >>>> ^ sum - sample >>> >>> >>> Thanks! Missed that. >>> >>>> >>>> On Sun, Dec 20, 2015 at 8:59 AM, Max Leske <[hidden email]> wrote: >>>> I would like to wrap up this discussion. >>>> >>>> >>>>> On 05 Dec 2015, at 18:14, stepharo <[hidden email]> wrote: >>>>> >>>>> So what is the conclusion? >>>>> I like the idea of Esteban M to have iterator because it moves some behavior out of core classes. >>>>> >>>>> [[[ >>>>> >>>>> aCollection arithmetic sum: [...] or.... aCollection >>>>> arithmetic avg. >>>>> >>>>> ]]] >>>>> >>>> >>>> While I think that iterators are an intriguing idea I also believe that they are beyond the scope of this issue. If anybody wants to follow up on iterators (or unit types for that matter) please start a new thread / issue. >>>> >>>> >>>> I propose to use Sven’s version for #sum:ifEmpty:. The result would be these three methods: >>>> >>>> sum >>>> ^ self >>>> sum: [ :each | each ] >>>> ifEmpty: [ 0 ] >>>> >>>> sum: aBlock >>>> ^ self >>>> sum: aBlock >>>> ifEmpty: [ self errorEmptyCollection ] >>>> >>>> sum: aBlock ifEmpty: emptyBlock >>>> | sum sample | >>>> self isEmpty ifTrue: [ ^ emptyBlock value ]. >>>> sample := self anyOne. >>>> sum := self >>>> inject: sample >>>> into: [ :accum :each | accum + (aBlock value: each) ]. >>>> ^ sum - sample >>>> >>>> >>>> I’ve attached a couple of benchmark results below. To me they show that >>>> 1. the new implementation is maybe a tiny bit slower but insignificantly so (if you’re going for performance you’ll probably write your own optimised version anyway) >>>> 2. there is no need to duplicate the code (like #sum and #sum: currently do). It’s perfectly fine to delegate to #sum:ifEmpty: >>>> >>>> >>>> >>>> In addition to the above changes I would like to remove #detectSum: (-> #sum:) and #sumNumbers (-> #sum). >>>> >>>> >>>> Note that once we agree on changing this API, we will need to also change #detectMin:, #detectMax:, #min, #max as well as all overrides (e.g. RunArray, Interval) of these and of #sum et. al. to stay consistent. The changes would of course be in line with this change, such that every operation has a unary selector with a sensible default, one that takes a block and throws an error for empty collections and a third that takes a block for the iteration and one for the empty case. >>>> >>>> >>>> Please cast your vote for these changes: >>>> >>>> 1. Do you agree to changing #sum and #sum: in the suggested way? >>>> 2. Do you agree to the removal of #detectSum:? ?? (not familiar) >>>> 3. Do you agree to the removal of #sumNumbers? yes >>>> 4. Do you agree that the #max and #min selectors also need to be adapted? ?? (not familiar) |
Also a good idea. However, looking at the methods on Collection, the pattern is usually #message and #message:, e.g. #sorted and #sorted:. There used to be #sortBy: but it was removed because the view was that the protocol semantics should be the same across all methods. The current case is a bit different of course since we’re dealing with the problem of the zero element which doesn’t arise in most other cases. Still, I think from a users point of view it would be strange to have to use #sumBy: when every other message pair uses the #message / #message: pattern. I feel that this argument (thanks Ben :) ) is also a valid point against Doru’s argument for #sumNumbers. While #sumNumbers may *technically* be the best name (which we can’t seem to agree on…), #sum, #sum: and #sum:ifEmpty: form a triple that naturally fits into the naming protocol applied elsewhere. Cheers, Max
|
Free forum by Nabble | Edit this page |