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 <[email protected]> wrote:



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


2015-12-27 2:49 GMT+01:00 Ben Coman <[email protected]>:
On Sun, Dec 27, 2015 at 6:13 AM, Nicolas Cellier
<[email protected]> wrote:

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

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

On Dec 4, 2015, at 12:49 AM, Ben Coman <[email protected]> wrote:

On Fri, Dec 4, 2015 at 4:23 AM, Nicolai Hess <[email protected]>
wrote:


2015-12-03 14:48 GMT+01:00 Ben Coman <[email protected]>:
On Wed, Dec 2, 2015 at 10:45 PM, Sven Van Caekenberghe <[email protected]>
wrote:
On 02 Dec 2015, at 15:21, Nicolai Hess <[email protected]>
wrote:



2015-12-02 15:03 GMT+01:00 Ben Coman <[email protected]>:
On Wed, Dec 2, 2015 at 12:38 AM, Tudor Girba <[email protected]>
wrote:
Hi,

On Dec 1, 2015, at 5:13 PM, Max Leske <[email protected]> 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
.  ..   ...    ^,^


Reply via email to