#sum:, #detectSum:, #sumNumbers:

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
97 messages Options
12345
Reply | Threaded
Open this post in threaded view
|

Re: #sum:, #detectSum:, #sumNumbers:

Max Leske
I did a pass on all the changes that would be required (whatever the outcome of this discussion). Looks easy enough. One interesting point: FloatArray>>sum is implemented as a primitive in the FloatArrayPlugin and the zero element is explicitly defined as 0.0. The primitive will not fail for an empty collection but return 0.0. That would be in line with our new definition of #sum.


One other thing: should the old selectors be marked as deprecated rather than being removed? I think that’s the general policy, right?

Cheers,
Max


On 20 Dec 2015, at 18:19, Max Leske <[hidden email]> wrote:


On 20 Dec 2015, at 15:26, Ben Coman <[hidden email]> wrote:

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.

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





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?
yes

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)


Reply | Threaded
Open this post in threaded view
|

Re: #sum:, #detectSum:, #sumNumbers:

Tudor Girba-2
Hi,

I cannot seem to agree with the current line of reasoning, so I am withdrawing from this debate. It’s late in the year and I know I need a break, so it is likely that I am missing something obvious or that I am just persisting in some sort of bike-shedding point of view :).

Thanks for keeping up with this.

I wish you all a lovely holiday and see you next year!

Doru


> On Dec 20, 2015, at 8:23 PM, Max Leske <[hidden email]> wrote:
>
> I did a pass on all the changes that would be required (whatever the outcome of this discussion). Looks easy enough. One interesting point: FloatArray>>sum is implemented as a primitive in the FloatArrayPlugin and the zero element is explicitly defined as 0.0. The primitive will not fail for an empty collection but return 0.0. That would be in line with our new definition of #sum.
>
>
> One other thing: should the old selectors be marked as deprecated rather than being removed? I think that’s the general policy, right?
>
> Cheers,
> Max
>
>
>> On 20 Dec 2015, at 18:19, Max Leske <[hidden email]> wrote:
>>
>>
>>> On 20 Dec 2015, at 15:26, Ben Coman <[hidden email]> wrote:
>>>
>>> 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.
>>
>> 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
>>
>>>
>>>
>>>
>>>>>
>>>>> 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?
>>> yes
>>>
>>>>>>> 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)
>>
>

--
www.tudorgirba.com
www.feenk.com

"Speaking louder won't make the point worthier."


Reply | Threaded
Open this post in threaded view
|

Re: #sum:, #detectSum:, #sumNumbers:

Sven Van Caekenberghe-2
I would suggest not to change anything for now, let's wait for Max's poll or feedback from others. We could also pick this up again when we see each other IRL, like at the Pharo Days, that will certainly make it easier.

> On 20 Dec 2015, at 22:09, Tudor Girba <[hidden email]> wrote:
>
> Hi,
>
> I cannot seem to agree with the current line of reasoning, so I am withdrawing from this debate. It’s late in the year and I know I need a break, so it is likely that I am missing something obvious or that I am just persisting in some sort of bike-shedding point of view :).
>
> Thanks for keeping up with this.
>
> I wish you all a lovely holiday and see you next year!
>
> Doru
>
>
>> On Dec 20, 2015, at 8:23 PM, Max Leske <[hidden email]> wrote:
>>
>> I did a pass on all the changes that would be required (whatever the outcome of this discussion). Looks easy enough. One interesting point: FloatArray>>sum is implemented as a primitive in the FloatArrayPlugin and the zero element is explicitly defined as 0.0. The primitive will not fail for an empty collection but return 0.0. That would be in line with our new definition of #sum.
>>
>>
>> One other thing: should the old selectors be marked as deprecated rather than being removed? I think that’s the general policy, right?
>>
>> Cheers,
>> Max
>>
>>
>>> On 20 Dec 2015, at 18:19, Max Leske <[hidden email]> wrote:
>>>
>>>
>>>> On 20 Dec 2015, at 15:26, Ben Coman <[hidden email]> wrote:
>>>>
>>>> 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.
>>>
>>> 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
>>>
>>>>
>>>>
>>>>
>>>>>>
>>>>>> 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?
>>>> yes
>>>>
>>>>>>>> 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)
>>>
>>
>
> --
> www.tudorgirba.com
> www.feenk.com
>
> "Speaking louder won't make the point worthier."
>
>


Reply | Threaded
Open this post in threaded view
|

Re: #sum:, #detectSum:, #sumNumbers:

Ben Coman
In reply to this post by Max Leske
On Wed, Dec 2, 2015 at 3:38 AM, Tudor Girba <[hidden email]> wrote:
> I am saying that if you want sum: to be generic, it cannot assume a *specific* Zero object.
> And sum:  should be generic because of its name.

This seems the crux of the disparate viewpoints, which is why I
suggested return a *generic* Zero object as follows...

> On 04 Dec 2015, at 01:49, Ben Coman <[hidden email]> wrote:
> do something like...
>
>    Collection>>sum
>       | sum sample |
>       self isEmpty ifTrue: [ ^ ArithmeticZero ].
>       sample := self anyOne.
>       sum := self inject: sample into: [ :accum :each | accum + each ].
>        ^ sum - sample

On Sat, Dec 5, 2015 at 3:12 AM, Max Leske <[hidden email]> wrote:
> 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.

Sure, small steps are better, except when this hits a sticking point
that the bigger step may overcome.  I think returning a generic zero
allowing the program to proceed is better than throwing an generic
error that the programmer needs to explicitly deal with.  The concept
of zero is well defined for the common arithmetic functions.  Just for
a thought experiment, what arithmetic functions would need to be dealt
with.

>    ArithmeticZero class >> + anObject
>        ^anObject

AritmeticZero class >> * anObject
     ^ anObject zero

AritmeticZero class >> - anObject
     ^ anObject zero - anObject


> 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.

Sure its an external package, but when you have a collection of weight
readings for example, you want to use the internal convenient #sum
method...
   { 4 kg . 5 kg . 6 kg } sum    --> 16kg
   { } sum + 1 kg     --> 1kg
   { } sum * 1 kg    --> 0 kg^2   "hmmm, zero with units and
multiplication starts getting more complicated - maybe should be left
out of this discussion"

> 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.

So maybe alternative naming of the generic zero...
#sum  (empty --> EmptyAggregateZero)
#sum:   (empty --> EmptyAggregateZero)
#sum: ifEmpty:   (empty --> whatever)


> 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.

#sum is very convenient and that lowers the barrier of entry for
newcomers over the relatively exotic #inject:into:    We should keep
trying to work through the sticky points, but maybe you guys getting
together IRL is better than continuing on the mail list.

cheers -ben

Reply | Threaded
Open this post in threaded view
|

Re: #sum:, #detectSum:, #sumNumbers:

Nicolas Cellier


2015-12-22 3:46 GMT+01:00 Ben Coman <[hidden email]>:
On Wed, Dec 2, 2015 at 3:38 AM, Tudor Girba <[hidden email]> wrote:
> I am saying that if you want sum: to be generic, it cannot assume a *specific* Zero object.
> And sum:  should be generic because of its name.

This seems the crux of the disparate viewpoints, which is why I
suggested return a *generic* Zero object as follows...

> On 04 Dec 2015, at 01:49, Ben Coman <[hidden email]> wrote:
> do something like...
>
>    Collection>>sum
>       | sum sample |
>       self isEmpty ifTrue: [ ^ ArithmeticZero ].
>       sample := self anyOne.
>       sum := self inject: sample into: [ :accum :each | accum + each ].
>        ^ sum - sample


Nice, but generic zero can't work: you sometimes need to decide if it is the zero of vector space, or of associated field.
The generic zero can't behave as both say a matrix and a scalar...
 
On Sat, Dec 5, 2015 at 3:12 AM, Max Leske <[hidden email]> wrote:
> 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.

Sure, small steps are better, except when this hits a sticking point
that the bigger step may overcome.  I think returning a generic zero
allowing the program to proceed is better than throwing an generic
error that the programmer needs to explicitly deal with.  The concept
of zero is well defined for the common arithmetic functions.  Just for
a thought experiment, what arithmetic functions would need to be dealt
with.

>    ArithmeticZero class >> + anObject
>        ^anObject

AritmeticZero class >> * anObject
     ^ anObject zero

AritmeticZero class >> - anObject
     ^ anObject zero - anObject


> 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.

Sure its an external package, but when you have a collection of weight
readings for example, you want to use the internal convenient #sum
method...
   { 4 kg . 5 kg . 6 kg } sum    --> 16kg
   { } sum + 1 kg     --> 1kg
   { } sum * 1 kg    --> 0 kg^2   "hmmm, zero with units and
multiplication starts getting more complicated - maybe should be left
out of this discussion"

> 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.

So maybe alternative naming of the generic zero...
#sum  (empty --> EmptyAggregateZero)
#sum:   (empty --> EmptyAggregateZero)
#sum: ifEmpty:   (empty --> whatever)


> 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.

#sum is very convenient and that lowers the barrier of entry for
newcomers over the relatively exotic #inject:into:    We should keep
trying to work through the sticky points, but maybe you guys getting
together IRL is better than continuing on the mail list.

cheers -ben


Reply | Threaded
Open this post in threaded view
|

Re: #sum:, #detectSum:, #sumNumbers:

Sven Van Caekenberghe-2

> On 22 Dec 2015, at 10:22, Nicolas Cellier <[hidden email]> wrote:
>
>
>
> 2015-12-22 3:46 GMT+01:00 Ben Coman <[hidden email]>:
> On Wed, Dec 2, 2015 at 3:38 AM, Tudor Girba <[hidden email]> wrote:
> > I am saying that if you want sum: to be generic, it cannot assume a *specific* Zero object.
> > And sum:  should be generic because of its name.
>
> This seems the crux of the disparate viewpoints, which is why I
> suggested return a *generic* Zero object as follows...
>
> > On 04 Dec 2015, at 01:49, Ben Coman <[hidden email]> wrote:
> > do something like...
> >
> >    Collection>>sum
> >       | sum sample |
> >       self isEmpty ifTrue: [ ^ ArithmeticZero ].
> >       sample := self anyOne.
> >       sum := self inject: sample into: [ :accum :each | accum + each ].
> >        ^ sum - sample
>
>
> Nice, but generic zero can't work: you sometimes need to decide if it is the zero of vector space, or of associated field.
> The generic zero can't behave as both say a matrix and a scalar...

Indeed, that is what I said the first time Ben proposed this.

But I am curious, Nicolas, what you think of this, with your math background/interest ?

> On Sat, Dec 5, 2015 at 3:12 AM, Max Leske <[hidden email]> wrote:
> > 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.
>
> Sure, small steps are better, except when this hits a sticking point
> that the bigger step may overcome.  I think returning a generic zero
> allowing the program to proceed is better than throwing an generic
> error that the programmer needs to explicitly deal with.  The concept
> of zero is well defined for the common arithmetic functions.  Just for
> a thought experiment, what arithmetic functions would need to be dealt
> with.
>
> >    ArithmeticZero class >> + anObject
> >        ^anObject
>
> AritmeticZero class >> * anObject
>      ^ anObject zero
>
> AritmeticZero class >> - anObject
>      ^ anObject zero - anObject
>
>
> > 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.
>
> Sure its an external package, but when you have a collection of weight
> readings for example, you want to use the internal convenient #sum
> method...
>    { 4 kg . 5 kg . 6 kg } sum    --> 16kg
>    { } sum + 1 kg     --> 1kg
>    { } sum * 1 kg    --> 0 kg^2   "hmmm, zero with units and
> multiplication starts getting more complicated - maybe should be left
> out of this discussion"
>
> > 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.
>
> So maybe alternative naming of the generic zero...
> #sum  (empty --> EmptyAggregateZero)
> #sum:   (empty --> EmptyAggregateZero)
> #sum: ifEmpty:   (empty --> whatever)
>
>
> > 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.
>
> #sum is very convenient and that lowers the barrier of entry for
> newcomers over the relatively exotic #inject:into:    We should keep
> trying to work through the sticky points, but maybe you guys getting
> together IRL is better than continuing on the mail list.
>
> cheers -ben


Reply | Threaded
Open this post in threaded view
|

Re: #sum:, #detectSum:, #sumNumbers:

Nicolas Cellier


2015-12-22 10:37 GMT+01:00 Sven Van Caekenberghe <[hidden email]>:

> On 22 Dec 2015, at 10:22, Nicolas Cellier <[hidden email]> wrote:
>
>
>
> 2015-12-22 3:46 GMT+01:00 Ben Coman <[hidden email]>:
> On Wed, Dec 2, 2015 at 3:38 AM, Tudor Girba <[hidden email]> wrote:
> > I am saying that if you want sum: to be generic, it cannot assume a *specific* Zero object.
> > And sum:  should be generic because of its name.
>
> This seems the crux of the disparate viewpoints, which is why I
> suggested return a *generic* Zero object as follows...
>
> > On 04 Dec 2015, at 01:49, Ben Coman <[hidden email]> wrote:
> > do something like...
> >
> >    Collection>>sum
> >       | sum sample |
> >       self isEmpty ifTrue: [ ^ ArithmeticZero ].
> >       sample := self anyOne.
> >       sum := self inject: sample into: [ :accum :each | accum + each ].
> >        ^ sum - sample
>
>
> Nice, but generic zero can't work: you sometimes need to decide if it is the zero of vector space, or of associated field.
> The generic zero can't behave as both say a matrix and a scalar...

Indeed, that is what I said the first time Ben proposed this.

But I am curious, Nicolas, what you think of this, with your math background/interest ?


This is what I had in old app (in the 90s):

SequenceableCollection>>sum: aBlock
    "answer the sum of all elements after applying a Block"
    | sum |
    self isEmpty ifTrue: [^0].
    sum := aBlock value: (self at: 1).
    2 to: self size do: [:i | sum := sum + (aBlock value: (self at: i))].
    ^sum

Collection>>sum: aBlock
    "answer the sum of all elements after applying a Block"
    | sum |
    sum := 0.
    self do: [:e | sum := sum + (aBlock value: e)].
    ^sum

I find sum: much more expressive than inject:into:

If we really find that it adds semantic value to inject:into: we may also implement optionnal:

Collection>>sum: aBlock to: initialValue
    "answer the sum of all elements after applying a Block"
    | sum |
    sum := initialValue.
    self do: [:e | sum := sum + (aBlock value: e)].
    ^sum
Collection>>sum: aBlock
    ^self sum: aBlock to: 0

This way, no (#anyOne,#-) trick required, that's why I prefer sum:to: to sum:ifEmpty:...
For example, I had symbolic algebra, and the #- trick would have required further simplification of the sum.

So I don't have any mathematical solution, just pragmatic ones:
- I agree on this: no need for many selectors, one or maximum two should be enough
- I wouldn't care too much and would just answer 0 for empty collection because we have inject:into: or optionnally sum:to: for exotic cases

Reply | Threaded
Open this post in threaded view
|

Re: #sum:, #detectSum:, #sumNumbers:

Denis Kudriashov
In reply to this post by Max Leske
Hi

My vote:


1. Do you agree to changing #sum and #sum: in the suggested way?
 
yes but I prefer #sum: return zero too for empty collections  


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?

yes
Reply | Threaded
Open this post in threaded view
|

Re: #sum:, #detectSum:, #sumNumbers:

Nicolai Hess-3-2
In reply to this post by Max Leske


2015-12-20 12:59 GMT+01:00 Max Leske <[hidden email]>:


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).

there is no #sumNumbers, only #sumNumbers:
 


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?

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?

hm. I like the "detect". If

aCollection detectMax: aBlock
becomes

aCollection max: aBlock

it looks too similar  to
aCollection size max: aValue

But  I could live with that :)




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


Reply | Threaded
Open this post in threaded view
|

Re: #sum:, #detectSum:, #sumNumbers:

CyrilFerlicot
In reply to this post by Max Leske
Le 20/12/2015 12:59, Max Leske a écrit :

> 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?
>
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?
>

Yes

>
>
> 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
>

--
Cyril Ferlicot

http://www.synectique.eu

165 Avenue Bretagne
Lille 59000 France


signature.asc (836 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: #sum:, #detectSum:, #sumNumbers:

stepharo
In reply to this post by Nicolas Cellier
Just a remark.
I think that we discarded the proposition of having

aCol arithmetic sum

but I found it nice because there if was clear that you want to get back
0 for #().

Stef

Reply | Threaded
Open this post in threaded view
|

Re: #sum:, #detectSum:, #sumNumbers:

stepharo
In reply to this post by Nicolas Cellier
Just a remark.
I think that we discarded the proposition of having

aCol arithmetic sum

but I found it nice because there if was clear that you want to get back
0 for #().

Stef

Reply | Threaded
Open this post in threaded view
|

Re: #sum:, #detectSum:, #sumNumbers:

Eliot Miranda-2
In reply to this post by Ben Coman
Ben,

_,,,^..^,,,_ (phone)

> On Dec 4, 2015, at 12:49 AM, Ben Coman <[hidden email]> wrote:
>
>> On Fri, Dec 4, 2015 at 4:23 AM, Nicolai Hess <[hidden email]> wrote:
>>
>>
>> 2015-12-03 14:48 GMT+01:00 Ben Coman <[hidden email]>:
>>>
>>> On Wed, Dec 2, 2015 at 10:45 PM, Sven Van Caekenberghe <[hidden email]>
>>> wrote:
>>>>
>>>>> On 02 Dec 2015, at 15:21, Nicolai Hess <[hidden email]> wrote:
>>>>>
>>>>>
>>>>>
>>>>> 2015-12-02 15:03 GMT+01:00 Ben Coman <[hidden email]>:
>>>>> On Wed, Dec 2, 2015 at 12:38 AM, Tudor Girba <[hidden email]>
>>>>> wrote:
>>>>>> Hi,
>>>>>>
>>>>>>> On Dec 1, 2015, at 5:13 PM, Max Leske <[hidden email]> wrote:
>>>>>>>
>>>>>>> @Doru
>>>>>>> You’re missing the point: #anyOne *fails* for empty collections.
>>>>>>
>>>>>> I am not missing the point at all. I am saying that if you want sum:
>>>>>> to be generic, it cannot assume a specific Zero object.
>>>>>>
>>>>>> And sum: should be generic because of its name.
>>>>>
>>>>> I am missing understanding the other use cases.  Can you describe
>>>>> further the generic nature of #sum & #sum: ?  I would have thought by
>>>>> default they only applied to numbers.
>>>>>
>>>>> sum can be applied to anything that supports #+, not only numbers
>>>>> sum: can be applied to any collection with a block that return some
>>>>> object that supports #+
>>>
>>> To me this is a mis-application of polymorphism, that just because
>>> something responds to #+ it should be summable. We have overloaded the
>>> semantics of  #+  to mean both numeric addition and
>>> concatenation/membership, but technically "summation" relates only to
>>> numeric addition.
>>
>>
>> I didn't wanted to argue for or against any change. I just wanted to clarify
>> that there are situations in which a generic sum/sum: that throws an error
>> on empty collections and don't assume a null value makes sense.
>>
>>
>>>
>>>
>>> https://www.google.com.au/search?q=define+sum&oq=define+sum
>>>
>>> https://www.google.com.au/search?q=define+concatenate&oq=define+concatenate
>>>
>>> For example...
>>>
>>> * KMModifier implements  #+  so what is the expected semantic of   " {
>>> KMModifier shift . KMModifier meta} sum " ?
>>> To me this is more of a concatenation/join/union facility rather than
>>> numeric addition.  (btw, that expression actually fails since
>>> KMModifier does not understand minus #- ) .
>>>
>>> * String implements  #+  and  " { '1' . '2' } sum " --> '3',   so
>>> actually its doing numeric addition.  However  " { 'a' . 'b' } sum "
>>> produces an error.
>>>
>>> So actually there seem some existing problems with summing
>>> non-numerics.  What examples work?
>>>
>>> * Trait classes implement both  #+  and  #- , but the semantic seems
>>> more to do with membership than numeric addition.  I don't how how to
>>> produce an example of using #sum against traits.
>>>
>>> * Points are summable  " { 2@2 . 3@3 } " --> 5@5.   But then  " 2@2 +
>>> 1 " --> 3@3   ,   so  " {} sum "  returning  0  would seem to not
>>> cause any error in this case.
>>>
>>>
>>> cheers -ben
>>>
>>>
>>>>>
>>>>> therefore you can not assume 0 (<- a number) is a proper initial value
>>>>> therefore you *need* to work with #anyOne
>>>>> and as you can not assume a proper initial value, you can not assume a
>>>>> default value for empty collections
>>>>> -> it should throw an error. If you (the caller of the function) knows
>>>>> what to do with an empty collection you have
>>>>> to check, or call inject:into: directly, with a proper initial value.
>>>>
>>>> I am sorry but I am getting really tired of this, you should read what
>>>> is being said.
>>
>>
>> do that change, I am not against it. Ben just asked for an example and I
>> thought it would be helpful.
>
> It was helpful :)  It evolved my thinking.   Now thinking further, I
> wonder how returning  0  will work with applications using units like
> Aconcagua, and if it would over-complicate things to do something
> like...
>
>    Collection>>sum
>       | sum sample |
>       self isEmpty ifTrue: [ ^ ArithmeticZero ].
>       sample := self anyOne.
>       sum := self inject: sample into: [ :accum :each | accum + each ].
>        ^ sum - sample
>
>    ArithmeticZero class >> + anObject
>        ^anObject

surely you mean

Collection>>sum
      ^self inject: ArithmeticZero into: [ :accum :each | accum + each ]

   ArithmeticZero class >> + anObject
       ^anObject

and I'd optimise as
Collection>>sum
      | sum |
      sum := ArithmeticZero.
      self do: [ :each | sum := sum + each ].
      ^sum

But in with those that want an error and would use either
Collection>>sum
      ^self inject: self anyOne species zero
               into: [ :accum :each | accum + each ]

or

Collection>>sum
      | sum |
      sum := self anyOne species zero.
      self do: [ :each | sum := sum + each ].
      ^sum

>
> cheers -ben
>
>>
>>
>>>
>>>>
>>>> I am not suggesting to stop using #anyOne because I like why it is there
>>>> and what it can do.
>>>>
>>>> The change I want is what happens with an empty collection when using
>>>> the simplest selector, #sum.
>>>>
>>>> I do not want to say to some collection of numbers #sumIfEmpty: [0],
>>>> because summing numbers starting from zero is the most common case and
>>>> everybody expects that, hence the unary selector fits.
>>>>
>>>> I want the less common cases to use the more complicated API, as in some
>>>> collection of colors #sumIfEmpty: [ Color black ]
>>>>
>>>> In my book that is common sense API design.
>>>>
>>>> Doing that I do no take anything away, because today you already have to
>>>> make sure the collection is not empty.
>>>>
>>>> The only change would be in the error behaviour. I think that is a
>>>> reasonable price to pay. Instead of having #anyOne fail, it will say that #+
>>>> cannot add 0 to some object, and in a comment we can point to the
>>>> alternative API.
>>
>>
>>
>>
>>>
>>>>
>>>> http://izquotes.com/quote/242740 right ?
>>>>
>>>>> cheers -ben
>>>>>
>>>>>>
>>>>>>>> On 01 Dec 2015, at 15:31, Esteban A. Maringolo
>>>>>>>> <[hidden email]> wrote:
>>>>>>>>
>>>>>>>> I don't want to be heretic (or too orthodox), but why not to
>>>>>>>> delegate
>>>>>>>> this behavior to other class (an iterator maybe?).
>>>>>>>>
>>>>>>>> It's too tempting adding these convenience methods to Collection
>>>>>>>> and/or subclasses, but anything that requires an explicit protocol
>>>>>>>> of
>>>>>>>> its elements is wrong, IMO.
>>>>>>>>
>>>>>>>> something like aCollection arithmetic sum: [...] or.... aCollection
>>>>>>>> arithmetic avg.
>
>
> On Fri, Dec 4, 2015 at 3:26 AM, Chris Cunningham
> <[hidden email]> wrote:
>> <uncontrolled snipping>
>>
>>> On Thu, Dec 3, 2015 at 5:48 AM, Ben Coman <[hidden email]> wrote:
>>> * Points are summable " { 2@2 . 3@3 } " --> 5@5. But then " 2@2 +
>>> 1 " --> 3@3 , so " {} sum " returning 0 would seem to not
>>> cause any error in this case.
>>
>> but points aren't commutative:
>>
>> 2@2 + 1 " = 3@3"
>> 1 + 2@2 " = 3@2"
>>
>> Of course, 0 wouldn't be an issue, unless you wanted to access x or y!
>

Reply | Threaded
Open this post in threaded view
|

Re: #sum:, #detectSum:, #sumNumbers:

Henrik Nergaard
In reply to this post by stepharo
Like this?
http://smalltalkhub.com/#!/~Latsabben/NumIt

Best regards,
Henrik

-----Original Message-----
From: Pharo-dev [mailto:[hidden email]] On Behalf Of stepharo
Sent: Thursday, December 24, 2015 9:58 AM
To: Pharo Development List <[hidden email]>
Subject: Re: [Pharo-dev] #sum:, #detectSum:, #sumNumbers:

Just a remark.
I think that we discarded the proposition of having

aCol arithmetic sum

but I found it nice because there if was clear that you want to get back
0 for #().

Stef

Reply | Threaded
Open this post in threaded view
|

Re: #sum:, #detectSum:, #sumNumbers:

Nicolas Cellier
In reply to this post by Eliot Miranda-2


2015-12-25 2:03 GMT+01:00 Eliot Miranda <[hidden email]>:
Ben,

_,,,^..^,,,_ (phone)

> On Dec 4, 2015, at 12:49 AM, Ben Coman <[hidden email]> wrote:
>
>> On Fri, Dec 4, 2015 at 4:23 AM, Nicolai Hess <[hidden email]> wrote:
>>
>>
>> 2015-12-03 14:48 GMT+01:00 Ben Coman <[hidden email]>:
>>>
>>> On Wed, Dec 2, 2015 at 10:45 PM, Sven Van Caekenberghe <[hidden email]>
>>> wrote:
>>>>
>>>>> On 02 Dec 2015, at 15:21, Nicolai Hess <[hidden email]> wrote:
>>>>>
>>>>>
>>>>>
>>>>> 2015-12-02 15:03 GMT+01:00 Ben Coman <[hidden email]>:
>>>>> On Wed, Dec 2, 2015 at 12:38 AM, Tudor Girba <[hidden email]>
>>>>> wrote:
>>>>>> Hi,
>>>>>>
>>>>>>> On Dec 1, 2015, at 5:13 PM, Max Leske <[hidden email]> wrote:
>>>>>>>
>>>>>>> @Doru
>>>>>>> You’re missing the point: #anyOne *fails* for empty collections.
>>>>>>
>>>>>> I am not missing the point at all. I am saying that if you want sum:
>>>>>> to be generic, it cannot assume a specific Zero object.
>>>>>>
>>>>>> And sum: should be generic because of its name.
>>>>>
>>>>> I am missing understanding the other use cases.  Can you describe
>>>>> further the generic nature of #sum & #sum: ?  I would have thought by
>>>>> default they only applied to numbers.
>>>>>
>>>>> sum can be applied to anything that supports #+, not only numbers
>>>>> sum: can be applied to any collection with a block that return some
>>>>> object that supports #+
>>>
>>> To me this is a mis-application of polymorphism, that just because
>>> something responds to #+ it should be summable. We have overloaded the
>>> semantics of  #+  to mean both numeric addition and
>>> concatenation/membership, but technically "summation" relates only to
>>> numeric addition.
>>
>>
>> I didn't wanted to argue for or against any change. I just wanted to clarify
>> that there are situations in which a generic sum/sum: that throws an error
>> on empty collections and don't assume a null value makes sense.
>>
>>
>>>
>>>
>>> https://www.google.com.au/search?q=define+sum&oq=define+sum
>>>
>>> https://www.google.com.au/search?q=define+concatenate&oq=define+concatenate
>>>
>>> For example...
>>>
>>> * KMModifier implements  #+  so what is the expected semantic of   " {
>>> KMModifier shift . KMModifier meta} sum " ?
>>> To me this is more of a concatenation/join/union facility rather than
>>> numeric addition.  (btw, that expression actually fails since
>>> KMModifier does not understand minus #- ) .
>>>
>>> * String implements  #+  and  " { '1' . '2' } sum " --> '3',   so
>>> actually its doing numeric addition.  However  " { 'a' . 'b' } sum "
>>> produces an error.
>>>
>>> So actually there seem some existing problems with summing
>>> non-numerics.  What examples work?
>>>
>>> * Trait classes implement both  #+  and  #- , but the semantic seems
>>> more to do with membership than numeric addition.  I don't how how to
>>> produce an example of using #sum against traits.
>>>
>>> * Points are summable  " { 2@2 . 3@3 } " --> 5@5.   But then  " 2@2 +
>>> 1 " --> 3@3   ,   so  " {} sum "  returning  0  would seem to not
>>> cause any error in this case.
>>>
>>>
>>> cheers -ben
>>>
>>>
>>>>>
>>>>> therefore you can not assume 0 (<- a number) is a proper initial value
>>>>> therefore you *need* to work with #anyOne
>>>>> and as you can not assume a proper initial value, you can not assume a
>>>>> default value for empty collections
>>>>> -> it should throw an error. If you (the caller of the function) knows
>>>>> what to do with an empty collection you have
>>>>> to check, or call inject:into: directly, with a proper initial value.
>>>>
>>>> I am sorry but I am getting really tired of this, you should read what
>>>> is being said.
>>
>>
>> do that change, I am not against it. Ben just asked for an example and I
>> thought it would be helpful.
>
> It was helpful :)  It evolved my thinking.   Now thinking further, I
> wonder how returning  0  will work with applications using units like
> Aconcagua, and if it would over-complicate things to do something
> like...
>
>    Collection>>sum
>       | sum sample |
>       self isEmpty ifTrue: [ ^ ArithmeticZero ].
>       sample := self anyOne.
>       sum := self inject: sample into: [ :accum :each | accum + each ].
>        ^ sum - sample
>
>    ArithmeticZero class >> + anObject
>        ^anObject

surely you mean

Collection>>sum
      ^self inject: ArithmeticZero into: [ :accum :each | accum + each ]

   ArithmeticZero class >> + anObject
       ^anObject

and I'd optimise as
Collection>>sum
      | sum |
      sum := ArithmeticZero.
      self do: [ :each | sum := sum + each ].
      ^sum

But in with those that want an error and would use either
Collection>>sum
      ^self inject: self anyOne species zero
               into: [ :accum :each | accum + each ]

or

Collection>>sum
      | sum |
      sum := self anyOne species zero.
      self do: [ :each | sum := sum + each ].
      ^sum


Not bad, but the class cannot allways determine the correct zero.
For example Matrix is too generic and can't guess about dimensions which are instance specific.
So zero should be instance specific.

Nicolas
Reply | Threaded
Open this post in threaded view
|

Re: #sum:, #detectSum:, #sumNumbers:

Ben Coman
On Sun, Dec 27, 2015 at 6:13 AM, Nicolas Cellier
<[hidden email]> wrote:

>
>
> 2015-12-25 2:03 GMT+01:00 Eliot Miranda <[hidden email]>:
>>
>> Ben,
>>
>> _,,,^..^,,,_ (phone)
>>
>> > On Dec 4, 2015, at 12:49 AM, Ben Coman <[hidden email]> wrote:
>> >
>> >> On Fri, Dec 4, 2015 at 4:23 AM, Nicolai Hess <[hidden email]>
>> >> wrote:
>> >>
>> >>
>> >> 2015-12-03 14:48 GMT+01:00 Ben Coman <[hidden email]>:
>> >>>
>> >>> On Wed, Dec 2, 2015 at 10:45 PM, Sven Van Caekenberghe <[hidden email]>
>> >>> wrote:
>> >>>>
>> >>>>> On 02 Dec 2015, at 15:21, Nicolai Hess <[hidden email]>
>> >>>>> wrote:
>> >>>>>
>> >>>>>
>> >>>>>
>> >>>>> 2015-12-02 15:03 GMT+01:00 Ben Coman <[hidden email]>:
>> >>>>> On Wed, Dec 2, 2015 at 12:38 AM, Tudor Girba <[hidden email]>
>> >>>>> wrote:
>> >>>>>> Hi,
>> >>>>>>
>> >>>>>>> On Dec 1, 2015, at 5:13 PM, Max Leske <[hidden email]> wrote:
>> >>>>>>>
>> >>>>>>> @Doru
>> >>>>>>> You’re missing the point: #anyOne *fails* for empty collections.
>> >>>>>>
>> >>>>>> I am not missing the point at all. I am saying that if you want
>> >>>>>> sum:
>> >>>>>> to be generic, it cannot assume a specific Zero object.
>> >>>>>>
>> >>>>>> And sum: should be generic because of its name.
>> >>>>>
>> >>>>> I am missing understanding the other use cases.  Can you describe
>> >>>>> further the generic nature of #sum & #sum: ?  I would have thought
>> >>>>> by
>> >>>>> default they only applied to numbers.
>> >>>>>
>> >>>>> sum can be applied to anything that supports #+, not only numbers
>> >>>>> sum: can be applied to any collection with a block that return some
>> >>>>> object that supports #+
>> >>>
>> >>> To me this is a mis-application of polymorphism, that just because
>> >>> something responds to #+ it should be summable. We have overloaded the
>> >>> semantics of  #+  to mean both numeric addition and
>> >>> concatenation/membership, but technically "summation" relates only to
>> >>> numeric addition.
>> >>
>> >>
>> >> I didn't wanted to argue for or against any change. I just wanted to
>> >> clarify
>> >> that there are situations in which a generic sum/sum: that throws an
>> >> error
>> >> on empty collections and don't assume a null value makes sense.
>> >>
>> >>
>> >>>
>> >>>
>> >>> https://www.google.com.au/search?q=define+sum&oq=define+sum
>> >>>
>> >>>
>> >>> https://www.google.com.au/search?q=define+concatenate&oq=define+concatenate
>> >>>
>> >>> For example...
>> >>>
>> >>> * KMModifier implements  #+  so what is the expected semantic of   " {
>> >>> KMModifier shift . KMModifier meta} sum " ?
>> >>> To me this is more of a concatenation/join/union facility rather than
>> >>> numeric addition.  (btw, that expression actually fails since
>> >>> KMModifier does not understand minus #- ) .
>> >>>
>> >>> * String implements  #+  and  " { '1' . '2' } sum " --> '3',   so
>> >>> actually its doing numeric addition.  However  " { 'a' . 'b' } sum "
>> >>> produces an error.
>> >>>
>> >>> So actually there seem some existing problems with summing
>> >>> non-numerics.  What examples work?
>> >>>
>> >>> * Trait classes implement both  #+  and  #- , but the semantic seems
>> >>> more to do with membership than numeric addition.  I don't how how to
>> >>> produce an example of using #sum against traits.
>> >>>
>> >>> * Points are summable  " { 2@2 . 3@3 } " --> 5@5.   But then  " 2@2 +
>> >>> 1 " --> 3@3   ,   so  " {} sum "  returning  0  would seem to not
>> >>> cause any error in this case.
>> >>>
>> >>>
>> >>> cheers -ben
>> >>>
>> >>>
>> >>>>>
>> >>>>> therefore you can not assume 0 (<- a number) is a proper initial
>> >>>>> value
>> >>>>> therefore you *need* to work with #anyOne
>> >>>>> and as you can not assume a proper initial value, you can not assume
>> >>>>> a
>> >>>>> default value for empty collections
>> >>>>> -> it should throw an error. If you (the caller of the function)
>> >>>>> knows
>> >>>>> what to do with an empty collection you have
>> >>>>> to check, or call inject:into: directly, with a proper initial
>> >>>>> value.
>> >>>>
>> >>>> I am sorry but I am getting really tired of this, you should read
>> >>>> what
>> >>>> is being said.
>> >>
>> >>
>> >> do that change, I am not against it. Ben just asked for an example and
>> >> I
>> >> thought it would be helpful.
>> >
>> > It was helpful :)  It evolved my thinking.   Now thinking further, I
>> > wonder how returning  0  will work with applications using units like
>> > Aconcagua, and if it would over-complicate things to do something
>> > like...
>> >
>> >    Collection>>sum
>> >       | sum sample |
>> >       self isEmpty ifTrue: [ ^ ArithmeticZero ].
>> >       sample := self anyOne.
>> >       sum := self inject: sample into: [ :accum :each | accum + each ].
>> >        ^ sum - sample
>> >
>> >    ArithmeticZero class >> + anObject
>> >        ^anObject
>>
>> surely you mean
>>
>> Collection>>sum
>>       ^self inject: ArithmeticZero into: [ :accum :each | accum + each ]
>>
>>    ArithmeticZero class >> + anObject
>>        ^anObject
>>
>> and I'd optimise as
>> Collection>>sum
>>       | sum |
>>       sum := ArithmeticZero.
>>       self do: [ :each | sum := sum + each ].
>>       ^sum
>>
>> But in with those that want an error and would use either
>> Collection>>sum
>>       ^self inject: self anyOne species zero
>>                into: [ :accum :each | accum + each ]
>>
>> or
>>
>> Collection>>sum
>>       | sum |
>>       sum := self anyOne species zero.
>>       self do: [ :each | sum := sum + each ].
>>       ^sum
>>
>
> Not bad, but the class cannot allways determine the correct zero.
> For example Matrix is too generic and can't guess about dimensions which are
> instance specific.
> So zero should be instance specific.

So if "species zero" isn't good to implement summing, could we use it
to delegate raising an error.
For example, cases like Matrix where summing an empty collection
should produce an error, this could be done by ArithmeticZero
delegating to the second operand to raise the error there?

ArithmeticZero >> + operand
    operand species zero + operand

Matrix class >> zero
    ErrorZeroDoesn'tMakeSense new signal.

?
cheers -ben

Reply | Threaded
Open this post in threaded view
|

Re: #sum:, #detectSum:, #sumNumbers:

Nicolas Cellier


2015-12-27 2:49 GMT+01:00 Ben Coman <[hidden email]>:
On Sun, Dec 27, 2015 at 6:13 AM, Nicolas Cellier
<[hidden email]> wrote:
>
>
> 2015-12-25 2:03 GMT+01:00 Eliot Miranda <[hidden email]>:
>>
>> Ben,
>>
>> _,,,^..^,,,_ (phone)
>>
>> > On Dec 4, 2015, at 12:49 AM, Ben Coman <[hidden email]> wrote:
>> >
>> >> On Fri, Dec 4, 2015 at 4:23 AM, Nicolai Hess <[hidden email]>
>> >> wrote:
>> >>
>> >>
>> >> 2015-12-03 14:48 GMT+01:00 Ben Coman <[hidden email]>:
>> >>>
>> >>> On Wed, Dec 2, 2015 at 10:45 PM, Sven Van Caekenberghe <[hidden email]>
>> >>> wrote:
>> >>>>
>> >>>>> On 02 Dec 2015, at 15:21, Nicolai Hess <[hidden email]>
>> >>>>> wrote:
>> >>>>>
>> >>>>>
>> >>>>>
>> >>>>> 2015-12-02 15:03 GMT+01:00 Ben Coman <[hidden email]>:
>> >>>>> On Wed, Dec 2, 2015 at 12:38 AM, Tudor Girba <[hidden email]>
>> >>>>> wrote:
>> >>>>>> Hi,
>> >>>>>>
>> >>>>>>> On Dec 1, 2015, at 5:13 PM, Max Leske <[hidden email]> wrote:
>> >>>>>>>
>> >>>>>>> @Doru
>> >>>>>>> You’re missing the point: #anyOne *fails* for empty collections.
>> >>>>>>
>> >>>>>> I am not missing the point at all. I am saying that if you want
>> >>>>>> sum:
>> >>>>>> to be generic, it cannot assume a specific Zero object.
>> >>>>>>
>> >>>>>> And sum: should be generic because of its name.
>> >>>>>
>> >>>>> I am missing understanding the other use cases.  Can you describe
>> >>>>> further the generic nature of #sum & #sum: ?  I would have thought
>> >>>>> by
>> >>>>> default they only applied to numbers.
>> >>>>>
>> >>>>> sum can be applied to anything that supports #+, not only numbers
>> >>>>> sum: can be applied to any collection with a block that return some
>> >>>>> object that supports #+
>> >>>
>> >>> To me this is a mis-application of polymorphism, that just because
>> >>> something responds to #+ it should be summable. We have overloaded the
>> >>> semantics of  #+  to mean both numeric addition and
>> >>> concatenation/membership, but technically "summation" relates only to
>> >>> numeric addition.
>> >>
>> >>
>> >> I didn't wanted to argue for or against any change. I just wanted to
>> >> clarify
>> >> that there are situations in which a generic sum/sum: that throws an
>> >> error
>> >> on empty collections and don't assume a null value makes sense.
>> >>
>> >>
>> >>>
>> >>>
>> >>> https://www.google.com.au/search?q=define+sum&oq=define+sum
>> >>>
>> >>>
>> >>> https://www.google.com.au/search?q=define+concatenate&oq=define+concatenate
>> >>>
>> >>> For example...
>> >>>
>> >>> * KMModifier implements  #+  so what is the expected semantic of   " {
>> >>> KMModifier shift . KMModifier meta} sum " ?
>> >>> To me this is more of a concatenation/join/union facility rather than
>> >>> numeric addition.  (btw, that expression actually fails since
>> >>> KMModifier does not understand minus #- ) .
>> >>>
>> >>> * String implements  #+  and  " { '1' . '2' } sum " --> '3',   so
>> >>> actually its doing numeric addition.  However  " { 'a' . 'b' } sum "
>> >>> produces an error.
>> >>>
>> >>> So actually there seem some existing problems with summing
>> >>> non-numerics.  What examples work?
>> >>>
>> >>> * Trait classes implement both  #+  and  #- , but the semantic seems
>> >>> more to do with membership than numeric addition.  I don't how how to
>> >>> produce an example of using #sum against traits.
>> >>>
>> >>> * Points are summable  " { 2@2 . 3@3 } " --> 5@5.   But then  " 2@2 +
>> >>> 1 " --> 3@3   ,   so  " {} sum "  returning  0  would seem to not
>> >>> cause any error in this case.
>> >>>
>> >>>
>> >>> cheers -ben
>> >>>
>> >>>
>> >>>>>
>> >>>>> therefore you can not assume 0 (<- a number) is a proper initial
>> >>>>> value
>> >>>>> therefore you *need* to work with #anyOne
>> >>>>> and as you can not assume a proper initial value, you can not assume
>> >>>>> a
>> >>>>> default value for empty collections
>> >>>>> -> it should throw an error. If you (the caller of the function)
>> >>>>> knows
>> >>>>> what to do with an empty collection you have
>> >>>>> to check, or call inject:into: directly, with a proper initial
>> >>>>> value.
>> >>>>
>> >>>> I am sorry but I am getting really tired of this, you should read
>> >>>> what
>> >>>> is being said.
>> >>
>> >>
>> >> do that change, I am not against it. Ben just asked for an example and
>> >> I
>> >> thought it would be helpful.
>> >
>> > It was helpful :)  It evolved my thinking.   Now thinking further, I
>> > wonder how returning  0  will work with applications using units like
>> > Aconcagua, and if it would over-complicate things to do something
>> > like...
>> >
>> >    Collection>>sum
>> >       | sum sample |
>> >       self isEmpty ifTrue: [ ^ ArithmeticZero ].
>> >       sample := self anyOne.
>> >       sum := self inject: sample into: [ :accum :each | accum + each ].
>> >        ^ sum - sample
>> >
>> >    ArithmeticZero class >> + anObject
>> >        ^anObject
>>
>> surely you mean
>>
>> Collection>>sum
>>       ^self inject: ArithmeticZero into: [ :accum :each | accum + each ]
>>
>>    ArithmeticZero class >> + anObject
>>        ^anObject
>>
>> and I'd optimise as
>> Collection>>sum
>>       | sum |
>>       sum := ArithmeticZero.
>>       self do: [ :each | sum := sum + each ].
>>       ^sum
>>
>> But in with those that want an error and would use either
>> Collection>>sum
>>       ^self inject: self anyOne species zero
>>                into: [ :accum :each | accum + each ]
>>
>> or
>>
>> Collection>>sum
>>       | sum |
>>       sum := self anyOne species zero.
>>       self do: [ :each | sum := sum + each ].
>>       ^sum
>>
>
> Not bad, but the class cannot allways determine the correct zero.
> For example Matrix is too generic and can't guess about dimensions which are
> instance specific.
> So zero should be instance specific.

So if "species zero" isn't good to implement summing, could we use it
to delegate raising an error.
For example, cases like Matrix where summing an empty collection
should produce an error, this could be done by ArithmeticZero
delegating to the second operand to raise the error there?

ArithmeticZero >> + operand
    operand species zero + operand

Matrix class >> zero
    ErrorZeroDoesn'tMakeSense new signal.

?
cheers -ben


No, becauseItMakesSenseAtInstanceSide, I'd rather say it like this:
if we want to adopt injecting zero into the sum, then let's make it an instance side message rather than class side.
It's a rather elegant solution, but remember only for a minor problem:
- That's only necessary for unordered Collection (since Sequenceable can just inject self first and start looping at index 2).
- And that does not solve the case of empty collections which cannot use anyOne

Nicolas

Reply | Threaded
Open this post in threaded view
|

Re: #sum:, #detectSum:, #sumNumbers:

Eliot Miranda-2


On Dec 27, 2015, at 1:52 PM, Nicolas Cellier <[hidden email]> wrote:



2015-12-27 2:49 GMT+01:00 Ben Coman <[hidden email]>:
On Sun, Dec 27, 2015 at 6:13 AM, Nicolas Cellier
<[hidden email]> wrote:
>
>
> 2015-12-25 2:03 GMT+01:00 Eliot Miranda <[hidden email]>:
>>
>> Ben,
>>
>> _,,,^..^,,,_ (phone)
>>
>> > On Dec 4, 2015, at 12:49 AM, Ben Coman <[hidden email]> wrote:
>> >
>> >> On Fri, Dec 4, 2015 at 4:23 AM, Nicolai Hess <[hidden email]>
>> >> wrote:
>> >>
>> >>
>> >> 2015-12-03 14:48 GMT+01:00 Ben Coman <[hidden email]>:
>> >>>
>> >>> On Wed, Dec 2, 2015 at 10:45 PM, Sven Van Caekenberghe <[hidden email]>
>> >>> wrote:
>> >>>>
>> >>>>> On 02 Dec 2015, at 15:21, Nicolai Hess <[hidden email]>
>> >>>>> wrote:
>> >>>>>
>> >>>>>
>> >>>>>
>> >>>>> 2015-12-02 15:03 GMT+01:00 Ben Coman <[hidden email]>:
>> >>>>> On Wed, Dec 2, 2015 at 12:38 AM, Tudor Girba <[hidden email]>
>> >>>>> wrote:
>> >>>>>> Hi,
>> >>>>>>
>> >>>>>>> On Dec 1, 2015, at 5:13 PM, Max Leske <[hidden email]> wrote:
>> >>>>>>>
>> >>>>>>> @Doru
>> >>>>>>> You’re missing the point: #anyOne *fails* for empty collections.
>> >>>>>>
>> >>>>>> I am not missing the point at all. I am saying that if you want
>> >>>>>> sum:
>> >>>>>> to be generic, it cannot assume a specific Zero object.
>> >>>>>>
>> >>>>>> And sum: should be generic because of its name.
>> >>>>>
>> >>>>> I am missing understanding the other use cases.  Can you describe
>> >>>>> further the generic nature of #sum & #sum: ?  I would have thought
>> >>>>> by
>> >>>>> default they only applied to numbers.
>> >>>>>
>> >>>>> sum can be applied to anything that supports #+, not only numbers
>> >>>>> sum: can be applied to any collection with a block that return some
>> >>>>> object that supports #+
>> >>>
>> >>> To me this is a mis-application of polymorphism, that just because
>> >>> something responds to #+ it should be summable. We have overloaded the
>> >>> semantics of  #+  to mean both numeric addition and
>> >>> concatenation/membership, but technically "summation" relates only to
>> >>> numeric addition.
>> >>
>> >>
>> >> I didn't wanted to argue for or against any change. I just wanted to
>> >> clarify
>> >> that there are situations in which a generic sum/sum: that throws an
>> >> error
>> >> on empty collections and don't assume a null value makes sense.
>> >>
>> >>
>> >>>
>> >>>
>> >>> https://www.google.com.au/search?q=define+sum&oq=define+sum
>> >>>
>> >>>
>> >>> https://www.google.com.au/search?q=define+concatenate&oq=define+concatenate
>> >>>
>> >>> For example...
>> >>>
>> >>> * KMModifier implements  #+  so what is the expected semantic of   " {
>> >>> KMModifier shift . KMModifier meta} sum " ?
>> >>> To me this is more of a concatenation/join/union facility rather than
>> >>> numeric addition.  (btw, that expression actually fails since
>> >>> KMModifier does not understand minus #- ) .
>> >>>
>> >>> * String implements  #+  and  " { '1' . '2' } sum " --> '3',   so
>> >>> actually its doing numeric addition.  However  " { 'a' . 'b' } sum "
>> >>> produces an error.
>> >>>
>> >>> So actually there seem some existing problems with summing
>> >>> non-numerics.  What examples work?
>> >>>
>> >>> * Trait classes implement both  #+  and  #- , but the semantic seems
>> >>> more to do with membership than numeric addition.  I don't how how to
>> >>> produce an example of using #sum against traits.
>> >>>
>> >>> * Points are summable  " { 2@2 . 3@3 } " --> 5@5.   But then  " 2@2 +
>> >>> 1 " --> 3@3   ,   so  " {} sum "  returning  0  would seem to not
>> >>> cause any error in this case.
>> >>>
>> >>>
>> >>> cheers -ben
>> >>>
>> >>>
>> >>>>>
>> >>>>> therefore you can not assume 0 (<- a number) is a proper initial
>> >>>>> value
>> >>>>> therefore you *need* to work with #anyOne
>> >>>>> and as you can not assume a proper initial value, you can not assume
>> >>>>> a
>> >>>>> default value for empty collections
>> >>>>> -> it should throw an error. If you (the caller of the function)
>> >>>>> knows
>> >>>>> what to do with an empty collection you have
>> >>>>> to check, or call inject:into: directly, with a proper initial
>> >>>>> value.
>> >>>>
>> >>>> I am sorry but I am getting really tired of this, you should read
>> >>>> what
>> >>>> is being said.
>> >>
>> >>
>> >> do that change, I am not against it. Ben just asked for an example and
>> >> I
>> >> thought it would be helpful.
>> >
>> > It was helpful :)  It evolved my thinking.   Now thinking further, I
>> > wonder how returning  0  will work with applications using units like
>> > Aconcagua, and if it would over-complicate things to do something
>> > like...
>> >
>> >    Collection>>sum
>> >       | sum sample |
>> >       self isEmpty ifTrue: [ ^ ArithmeticZero ].
>> >       sample := self anyOne.
>> >       sum := self inject: sample into: [ :accum :each | accum + each ].
>> >        ^ sum - sample
>> >
>> >    ArithmeticZero class >> + anObject
>> >        ^anObject
>>
>> surely you mean
>>
>> Collection>>sum
>>       ^self inject: ArithmeticZero into: [ :accum :each | accum + each ]
>>
>>    ArithmeticZero class >> + anObject
>>        ^anObject
>>
>> and I'd optimise as
>> Collection>>sum
>>       | sum |
>>       sum := ArithmeticZero.
>>       self do: [ :each | sum := sum + each ].
>>       ^sum
>>
>> But in with those that want an error and would use either
>> Collection>>sum
>>       ^self inject: self anyOne species zero
>>                into: [ :accum :each | accum + each ]
>>
>> or
>>
>> Collection>>sum
>>       | sum |
>>       sum := self anyOne species zero.
>>       self do: [ :each | sum := sum + each ].
>>       ^sum
>>
>
> Not bad, but the class cannot allways determine the correct zero.
> For example Matrix is too generic and can't guess about dimensions which are
> instance specific.
> So zero should be instance specific.

So if "species zero" isn't good to implement summing, could we use it
to delegate raising an error.
For example, cases like Matrix where summing an empty collection
should produce an error, this could be done by ArithmeticZero
delegating to the second operand to raise the error there?

ArithmeticZero >> + operand
    operand species zero + operand

Matrix class >> zero
    ErrorZeroDoesn'tMakeSense new signal.

?
cheers -ben


No, becauseItMakesSenseAtInstanceSide, I'd rather say it like this:
if we want to adopt injecting zero into the sum, then let's make it an instance side message rather than class side.

+1, so it becomes eg

Collection>>sum
       | sum |
       sum := self anyOne asZero.
       self do: [ :each | sum := sum + each ].
       ^sum

and a Matrix can respond to asZero by answering a suitably dimensioned zero instance.  And if product were implemented, to asUnity with a suitable "one".

It's a rather elegant solution, but remember only for a minor problem:
- That's only necessary for unordered Collection (since Sequenceable can just inject self first and start looping at index 2).
- And that does not solve the case of empty collections which cannot use anyOne

I thought the conclusion was that empty collections /should/ error since the type of zero is undefined.  So if anyOne errors and sum included in its comment an explanation of it being undefined if empty and why then we're good.


Nicolas

Reply | Threaded
Open this post in threaded view
|

Re: #sum:, #detectSum:, #sumNumbers:

Sven Van Caekenberghe-2
Well, I beg to disagree, #sum on an empty collection should return 0.

https://en.wikipedia.org/wiki/Empty_sum

We do not need more tricks, the current trick with #anyOne is more than enough, that is not the problem.

The problem is that it is impossible to talk about sum (in the general most common sense) without assuming that the collection should have contained numbers, where 0 is the neutral element.

The #anyOne trick solves the problem of the neutral element for non empty collection, but leaves it unsolved for empty collections.

Defining it so that empty collections error is really silly: check the senders, most of them are then forced to check before calling #sum. In that case, they could all just as well have used #inject:into: for the same amount of code.

> On 28 Dec 2015, at 21:08, Eliot Miranda <[hidden email]> wrote:
>
>
>
> On Dec 27, 2015, at 1:52 PM, Nicolas Cellier <[hidden email]> wrote:
>
>>
>>
>> 2015-12-27 2:49 GMT+01:00 Ben Coman <[hidden email]>:
>> On Sun, Dec 27, 2015 at 6:13 AM, Nicolas Cellier
>> <[hidden email]> wrote:
>> >
>> >
>> > 2015-12-25 2:03 GMT+01:00 Eliot Miranda <[hidden email]>:
>> >>
>> >> Ben,
>> >>
>> >> _,,,^..^,,,_ (phone)
>> >>
>> >> > On Dec 4, 2015, at 12:49 AM, Ben Coman <[hidden email]> wrote:
>> >> >
>> >> >> On Fri, Dec 4, 2015 at 4:23 AM, Nicolai Hess <[hidden email]>
>> >> >> wrote:
>> >> >>
>> >> >>
>> >> >> 2015-12-03 14:48 GMT+01:00 Ben Coman <[hidden email]>:
>> >> >>>
>> >> >>> On Wed, Dec 2, 2015 at 10:45 PM, Sven Van Caekenberghe <[hidden email]>
>> >> >>> wrote:
>> >> >>>>
>> >> >>>>> On 02 Dec 2015, at 15:21, Nicolai Hess <[hidden email]>
>> >> >>>>> wrote:
>> >> >>>>>
>> >> >>>>>
>> >> >>>>>
>> >> >>>>> 2015-12-02 15:03 GMT+01:00 Ben Coman <[hidden email]>:
>> >> >>>>> On Wed, Dec 2, 2015 at 12:38 AM, Tudor Girba <[hidden email]>
>> >> >>>>> wrote:
>> >> >>>>>> Hi,
>> >> >>>>>>
>> >> >>>>>>> On Dec 1, 2015, at 5:13 PM, Max Leske <[hidden email]> wrote:
>> >> >>>>>>>
>> >> >>>>>>> @Doru
>> >> >>>>>>> You’re missing the point: #anyOne *fails* for empty collections.
>> >> >>>>>>
>> >> >>>>>> I am not missing the point at all. I am saying that if you want
>> >> >>>>>> sum:
>> >> >>>>>> to be generic, it cannot assume a specific Zero object.
>> >> >>>>>>
>> >> >>>>>> And sum: should be generic because of its name.
>> >> >>>>>
>> >> >>>>> I am missing understanding the other use cases.  Can you describe
>> >> >>>>> further the generic nature of #sum & #sum: ?  I would have thought
>> >> >>>>> by
>> >> >>>>> default they only applied to numbers.
>> >> >>>>>
>> >> >>>>> sum can be applied to anything that supports #+, not only numbers
>> >> >>>>> sum: can be applied to any collection with a block that return some
>> >> >>>>> object that supports #+
>> >> >>>
>> >> >>> To me this is a mis-application of polymorphism, that just because
>> >> >>> something responds to #+ it should be summable. We have overloaded the
>> >> >>> semantics of  #+  to mean both numeric addition and
>> >> >>> concatenation/membership, but technically "summation" relates only to
>> >> >>> numeric addition.
>> >> >>
>> >> >>
>> >> >> I didn't wanted to argue for or against any change. I just wanted to
>> >> >> clarify
>> >> >> that there are situations in which a generic sum/sum: that throws an
>> >> >> error
>> >> >> on empty collections and don't assume a null value makes sense.
>> >> >>
>> >> >>
>> >> >>>
>> >> >>>
>> >> >>> https://www.google.com.au/search?q=define+sum&oq=define+sum
>> >> >>>
>> >> >>>
>> >> >>> https://www.google.com.au/search?q=define+concatenate&oq=define+concatenate
>> >> >>>
>> >> >>> For example...
>> >> >>>
>> >> >>> * KMModifier implements  #+  so what is the expected semantic of   " {
>> >> >>> KMModifier shift . KMModifier meta} sum " ?
>> >> >>> To me this is more of a concatenation/join/union facility rather than
>> >> >>> numeric addition.  (btw, that expression actually fails since
>> >> >>> KMModifier does not understand minus #- ) .
>> >> >>>
>> >> >>> * String implements  #+  and  " { '1' . '2' } sum " --> '3',   so
>> >> >>> actually its doing numeric addition.  However  " { 'a' . 'b' } sum "
>> >> >>> produces an error.
>> >> >>>
>> >> >>> So actually there seem some existing problems with summing
>> >> >>> non-numerics.  What examples work?
>> >> >>>
>> >> >>> * Trait classes implement both  #+  and  #- , but the semantic seems
>> >> >>> more to do with membership than numeric addition.  I don't how how to
>> >> >>> produce an example of using #sum against traits.
>> >> >>>
>> >> >>> * Points are summable  " { 2@2 . 3@3 } " --> 5@5.   But then  " 2@2 +
>> >> >>> 1 " --> 3@3   ,   so  " {} sum "  returning  0  would seem to not
>> >> >>> cause any error in this case.
>> >> >>>
>> >> >>>
>> >> >>> cheers -ben
>> >> >>>
>> >> >>>
>> >> >>>>>
>> >> >>>>> therefore you can not assume 0 (<- a number) is a proper initial
>> >> >>>>> value
>> >> >>>>> therefore you *need* to work with #anyOne
>> >> >>>>> and as you can not assume a proper initial value, you can not assume
>> >> >>>>> a
>> >> >>>>> default value for empty collections
>> >> >>>>> -> it should throw an error. If you (the caller of the function)
>> >> >>>>> knows
>> >> >>>>> what to do with an empty collection you have
>> >> >>>>> to check, or call inject:into: directly, with a proper initial
>> >> >>>>> value.
>> >> >>>>
>> >> >>>> I am sorry but I am getting really tired of this, you should read
>> >> >>>> what
>> >> >>>> is being said.
>> >> >>
>> >> >>
>> >> >> do that change, I am not against it. Ben just asked for an example and
>> >> >> I
>> >> >> thought it would be helpful.
>> >> >
>> >> > It was helpful :)  It evolved my thinking.   Now thinking further, I
>> >> > wonder how returning  0  will work with applications using units like
>> >> > Aconcagua, and if it would over-complicate things to do something
>> >> > like...
>> >> >
>> >> >    Collection>>sum
>> >> >       | sum sample |
>> >> >       self isEmpty ifTrue: [ ^ ArithmeticZero ].
>> >> >       sample := self anyOne.
>> >> >       sum := self inject: sample into: [ :accum :each | accum + each ].
>> >> >        ^ sum - sample
>> >> >
>> >> >    ArithmeticZero class >> + anObject
>> >> >        ^anObject
>> >>
>> >> surely you mean
>> >>
>> >> Collection>>sum
>> >>       ^self inject: ArithmeticZero into: [ :accum :each | accum + each ]
>> >>
>> >>    ArithmeticZero class >> + anObject
>> >>        ^anObject
>> >>
>> >> and I'd optimise as
>> >> Collection>>sum
>> >>       | sum |
>> >>       sum := ArithmeticZero.
>> >>       self do: [ :each | sum := sum + each ].
>> >>       ^sum
>> >>
>> >> But in with those that want an error and would use either
>> >> Collection>>sum
>> >>       ^self inject: self anyOne species zero
>> >>                into: [ :accum :each | accum + each ]
>> >>
>> >> or
>> >>
>> >> Collection>>sum
>> >>       | sum |
>> >>       sum := self anyOne species zero.
>> >>       self do: [ :each | sum := sum + each ].
>> >>       ^sum
>> >>
>> >
>> > Not bad, but the class cannot allways determine the correct zero.
>> > For example Matrix is too generic and can't guess about dimensions which are
>> > instance specific.
>> > So zero should be instance specific.
>>
>> So if "species zero" isn't good to implement summing, could we use it
>> to delegate raising an error.
>> For example, cases like Matrix where summing an empty collection
>> should produce an error, this could be done by ArithmeticZero
>> delegating to the second operand to raise the error there?
>>
>> ArithmeticZero >> + operand
>>     operand species zero + operand
>>
>> Matrix class >> zero
>>     ErrorZeroDoesn'tMakeSense new signal.
>>
>> ?
>> cheers -ben
>>
>>
>> No, becauseItMakesSenseAtInstanceSide, I'd rather say it like this:
>> if we want to adopt injecting zero into the sum, then let's make it an instance side message rather than class side.
>
> +1, so it becomes eg
>
> Collection>>sum
>        | sum |
>        sum := self anyOne asZero.
>        self do: [ :each | sum := sum + each ].
>        ^sum
>
> and a Matrix can respond to asZero by answering a suitably dimensioned zero instance.  And if product were implemented, to asUnity with a suitable "one".
>
>> It's a rather elegant solution, but remember only for a minor problem:
>> - That's only necessary for unordered Collection (since Sequenceable can just inject self first and start looping at index 2).
>> - And that does not solve the case of empty collections which cannot use anyOne
>
> I thought the conclusion was that empty collections /should/ error since the type of zero is undefined.  So if anyOne errors and sum included in its comment an explanation of it being undefined if empty and why then we're good.
>
>>
>> Nicolas


Reply | Threaded
Open this post in threaded view
|

Re: #sum:, #detectSum:, #sumNumbers:

Robert Withers
This is sounding like a type inference situation.

On 12/28/2015 03:20 PM, Sven Van Caekenberghe wrote:

> Well, I beg to disagree, #sum on an empty collection should return 0.
>
> https://en.wikipedia.org/wiki/Empty_sum
>
> We do not need more tricks, the current trick with #anyOne is more than enough, that is not the problem.
>
> The problem is that it is impossible to talk about sum (in the general most common sense) without assuming that the collection should have contained numbers, where 0 is the neutral element.
>
> The #anyOne trick solves the problem of the neutral element for non empty collection, but leaves it unsolved for empty collections.
>
> Defining it so that empty collections error is really silly: check the senders, most of them are then forced to check before calling #sum. In that case, they could all just as well have used #inject:into: for the same amount of code.
>
>> On 28 Dec 2015, at 21:08, Eliot Miranda <[hidden email]> wrote:
>>
>>
>>
>> On Dec 27, 2015, at 1:52 PM, Nicolas Cellier <[hidden email]> wrote:
>>
>>>
>>> 2015-12-27 2:49 GMT+01:00 Ben Coman <[hidden email]>:
>>> On Sun, Dec 27, 2015 at 6:13 AM, Nicolas Cellier
>>> <[hidden email]> wrote:
>>>>
>>>> 2015-12-25 2:03 GMT+01:00 Eliot Miranda <[hidden email]>:
>>>>> Ben,
>>>>>
>>>>> _,,,^..^,,,_ (phone)
>>>>>
>>>>>> On Dec 4, 2015, at 12:49 AM, Ben Coman <[hidden email]> wrote:
>>>>>>
>>>>>>> On Fri, Dec 4, 2015 at 4:23 AM, Nicolai Hess <[hidden email]>
>>>>>>> wrote:
>>>>>>>
>>>>>>>
>>>>>>> 2015-12-03 14:48 GMT+01:00 Ben Coman <[hidden email]>:
>>>>>>>> On Wed, Dec 2, 2015 at 10:45 PM, Sven Van Caekenberghe <[hidden email]>
>>>>>>>> wrote:
>>>>>>>>>> On 02 Dec 2015, at 15:21, Nicolai Hess <[hidden email]>
>>>>>>>>>> wrote:
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> 2015-12-02 15:03 GMT+01:00 Ben Coman <[hidden email]>:
>>>>>>>>>> On Wed, Dec 2, 2015 at 12:38 AM, Tudor Girba <[hidden email]>
>>>>>>>>>> wrote:
>>>>>>>>>>> Hi,
>>>>>>>>>>>
>>>>>>>>>>>> On Dec 1, 2015, at 5:13 PM, Max Leske <[hidden email]> wrote:
>>>>>>>>>>>>
>>>>>>>>>>>> @Doru
>>>>>>>>>>>> You’re missing the point: #anyOne *fails* for empty collections.
>>>>>>>>>>> I am not missing the point at all. I am saying that if you want
>>>>>>>>>>> sum:
>>>>>>>>>>> to be generic, it cannot assume a specific Zero object.
>>>>>>>>>>>
>>>>>>>>>>> And sum: should be generic because of its name.
>>>>>>>>>> I am missing understanding the other use cases.  Can you describe
>>>>>>>>>> further the generic nature of #sum & #sum: ?  I would have thought
>>>>>>>>>> by
>>>>>>>>>> default they only applied to numbers.
>>>>>>>>>>
>>>>>>>>>> sum can be applied to anything that supports #+, not only numbers
>>>>>>>>>> sum: can be applied to any collection with a block that return some
>>>>>>>>>> object that supports #+
>>>>>>>> To me this is a mis-application of polymorphism, that just because
>>>>>>>> something responds to #+ it should be summable. We have overloaded the
>>>>>>>> semantics of  #+  to mean both numeric addition and
>>>>>>>> concatenation/membership, but technically "summation" relates only to
>>>>>>>> numeric addition.
>>>>>>>
>>>>>>> I didn't wanted to argue for or against any change. I just wanted to
>>>>>>> clarify
>>>>>>> that there are situations in which a generic sum/sum: that throws an
>>>>>>> error
>>>>>>> on empty collections and don't assume a null value makes sense.
>>>>>>>
>>>>>>>
>>>>>>>>
>>>>>>>> https://www.google.com.au/search?q=define+sum&oq=define+sum
>>>>>>>>
>>>>>>>>
>>>>>>>> https://www.google.com.au/search?q=define+concatenate&oq=define+concatenate
>>>>>>>>
>>>>>>>> For example...
>>>>>>>>
>>>>>>>> * KMModifier implements  #+  so what is the expected semantic of   " {
>>>>>>>> KMModifier shift . KMModifier meta} sum " ?
>>>>>>>> To me this is more of a concatenation/join/union facility rather than
>>>>>>>> numeric addition.  (btw, that expression actually fails since
>>>>>>>> KMModifier does not understand minus #- ) .
>>>>>>>>
>>>>>>>> * String implements  #+  and  " { '1' . '2' } sum " --> '3',   so
>>>>>>>> actually its doing numeric addition.  However  " { 'a' . 'b' } sum "
>>>>>>>> produces an error.
>>>>>>>>
>>>>>>>> So actually there seem some existing problems with summing
>>>>>>>> non-numerics.  What examples work?
>>>>>>>>
>>>>>>>> * Trait classes implement both  #+  and  #- , but the semantic seems
>>>>>>>> more to do with membership than numeric addition.  I don't how how to
>>>>>>>> produce an example of using #sum against traits.
>>>>>>>>
>>>>>>>> * Points are summable  " { 2@2 . 3@3 } " --> 5@5.   But then  " 2@2 +
>>>>>>>> 1 " --> 3@3   ,   so  " {} sum "  returning  0  would seem to not
>>>>>>>> cause any error in this case.
>>>>>>>>
>>>>>>>>
>>>>>>>> cheers -ben
>>>>>>>>
>>>>>>>>
>>>>>>>>>> therefore you can not assume 0 (<- a number) is a proper initial
>>>>>>>>>> value
>>>>>>>>>> therefore you *need* to work with #anyOne
>>>>>>>>>> and as you can not assume a proper initial value, you can not assume
>>>>>>>>>> a
>>>>>>>>>> default value for empty collections
>>>>>>>>>> -> it should throw an error. If you (the caller of the function)
>>>>>>>>>> knows
>>>>>>>>>> what to do with an empty collection you have
>>>>>>>>>> to check, or call inject:into: directly, with a proper initial
>>>>>>>>>> value.
>>>>>>>>> I am sorry but I am getting really tired of this, you should read
>>>>>>>>> what
>>>>>>>>> is being said.
>>>>>>>
>>>>>>> do that change, I am not against it. Ben just asked for an example and
>>>>>>> I
>>>>>>> thought it would be helpful.
>>>>>> It was helpful :)  It evolved my thinking.   Now thinking further, I
>>>>>> wonder how returning  0  will work with applications using units like
>>>>>> Aconcagua, and if it would over-complicate things to do something
>>>>>> like...
>>>>>>
>>>>>>     Collection>>sum
>>>>>>        | sum sample |
>>>>>>        self isEmpty ifTrue: [ ^ ArithmeticZero ].
>>>>>>        sample := self anyOne.
>>>>>>        sum := self inject: sample into: [ :accum :each | accum + each ].
>>>>>>         ^ sum - sample
>>>>>>
>>>>>>     ArithmeticZero class >> + anObject
>>>>>>         ^anObject
>>>>> surely you mean
>>>>>
>>>>> Collection>>sum
>>>>>        ^self inject: ArithmeticZero into: [ :accum :each | accum + each ]
>>>>>
>>>>>     ArithmeticZero class >> + anObject
>>>>>         ^anObject
>>>>>
>>>>> and I'd optimise as
>>>>> Collection>>sum
>>>>>        | sum |
>>>>>        sum := ArithmeticZero.
>>>>>        self do: [ :each | sum := sum + each ].
>>>>>        ^sum
>>>>>
>>>>> But in with those that want an error and would use either
>>>>> Collection>>sum
>>>>>        ^self inject: self anyOne species zero
>>>>>                 into: [ :accum :each | accum + each ]
>>>>>
>>>>> or
>>>>>
>>>>> Collection>>sum
>>>>>        | sum |
>>>>>        sum := self anyOne species zero.
>>>>>        self do: [ :each | sum := sum + each ].
>>>>>        ^sum
>>>>>
>>>> Not bad, but the class cannot allways determine the correct zero.
>>>> For example Matrix is too generic and can't guess about dimensions which are
>>>> instance specific.
>>>> So zero should be instance specific.
>>> So if "species zero" isn't good to implement summing, could we use it
>>> to delegate raising an error.
>>> For example, cases like Matrix where summing an empty collection
>>> should produce an error, this could be done by ArithmeticZero
>>> delegating to the second operand to raise the error there?
>>>
>>> ArithmeticZero >> + operand
>>>      operand species zero + operand
>>>
>>> Matrix class >> zero
>>>      ErrorZeroDoesn'tMakeSense new signal.
>>>
>>> ?
>>> cheers -ben
>>>
>>>
>>> No, becauseItMakesSenseAtInstanceSide, I'd rather say it like this:
>>> if we want to adopt injecting zero into the sum, then let's make it an instance side message rather than class side.
>> +1, so it becomes eg
>>
>> Collection>>sum
>>         | sum |
>>         sum := self anyOne asZero.
>>         self do: [ :each | sum := sum + each ].
>>         ^sum
>>
>> and a Matrix can respond to asZero by answering a suitably dimensioned zero instance.  And if product were implemented, to asUnity with a suitable "one".
>>
>>> It's a rather elegant solution, but remember only for a minor problem:
>>> - That's only necessary for unordered Collection (since Sequenceable can just inject self first and start looping at index 2).
>>> - And that does not solve the case of empty collections which cannot use anyOne
>> I thought the conclusion was that empty collections /should/ error since the type of zero is undefined.  So if anyOne errors and sum included in its comment an explanation of it being undefined if empty and why then we're good.
>>
>>> Nicolas
>

--
Robert
.  ..   ...    ^,^


12345