Skip Menu |

This queue is for tickets about the Scalar-List-Utils CPAN distribution.

Report information
The Basics
Id: 76172
Status: resolved
Priority: 0/
Queue: Scalar-List-Utils

People
Owner: Nobody in particular
Requestors: MAUKE [...] cpan.org
Cc: ether [...] cpan.org
AdminCc:

Bug Information
Severity: Normal
Broken in: 1.25
Fixed in: 1.26



Subject: sum() should return 0
sum(@xs) returns undef if @xs is empty. It should return 0 instead. I know the documentation says to call it as sum(0, @xs) but IMHO this behavior is simply broken, so why should I have to work around it in my code? I'm tired of having to define sub sum { List::Util::sum 0, @_ } every time I want to use this function. NB: In Haskell, sum [] == 0 and product [] == 1, because sum = reduce { $a + $b } 0, @xs and product = reduce { $a * $b } 1, @xs.
On Fri Mar 30 14:27:00 2012, MAUKE wrote: Show quoted text
> NB: In Haskell, sum [] == 0 and product [] == 1, because sum = reduce { > $a + $b } 0, @xs and product = reduce { $a * $b } 1, @xs.
At first glance those sound sensible, yes. I'll take a look for the next version. -- Paul Evans
Subject: Re: [rt.cpan.org #76172] sum() should return 0
Date: Mon, 16 Apr 2012 07:22:28 -0500
To: bug-Scalar-List-Utils [...] rt.cpan.org
From: Graham Barr <gbarr [...] pobox.com>
On Apr 15, 2012, at 16:15 , Paul Evans via RT wrote: Show quoted text
> Queue: Scalar-List-Utils > Ticket <URL: https://rt.cpan.org/Ticket/Display.html?id=76172 > > > On Fri Mar 30 14:27:00 2012, MAUKE wrote:
>> NB: In Haskell, sum [] == 0 and product [] == 1, because sum = reduce { >> $a + $b } 0, @xs and product = reduce { $a * $b } 1, @xs.
> > At first glance those sound sensible, yes. I'll take a look for the next > version.
It was a deliberate design decision for it to return undef when the argument list was empty and I can guarantee that changing it will break existing code and suggest you do not change it. Graham.
Then how about sub sum0 { sum 0, @_ } sub product1 { product 1, @_ } ? -- Paul Evans
Subject: Re: [rt.cpan.org #76172] sum() should return 0
Date: Mon, 16 Apr 2012 09:23:30 -0500
To: bug-Scalar-List-Utils [...] rt.cpan.org
From: Graham Barr <gbarr [...] pobox.com>
On Apr 16, 2012, at 07:59 , Paul Evans via RT wrote: Show quoted text
> Queue: Scalar-List-Utils > Ticket <URL: https://rt.cpan.org/Ticket/Display.html?id=76172 > > > Then how about > > sub sum0 { sum 0, @_ } > sub product1 { product 1, @_ }
I do not think that has any benefit over the caller explicitly passing the identity as the documentation suggests. IMO this addiition needlessly adds to List::Util. IMO, there is nothing to be done for this ticket. Graham.
I also feel that it would be much more useful for sum() to return 0. The minimum value of an empty list is not defined, so min() giving undef makes perfect sense, but that doesn't generalize to the sum. But you're right that for good or bad it is documented to return undef, and there may be code relying on this (though I would expect to see at least as much code 'relying' on the incorrect assumption that a number is always returned). One way forward would be to specify the behaviour at import time: use List::Util qw(sum0) Here you still get 'sum' imported but with the more sensible behaviour.
Subject: Re: [rt.cpan.org #76172] sum() should return 0
Date: Thu, 1 Nov 2012 09:07:41 -0500
To: bug-Scalar-List-Utils [...] rt.cpan.org
From: Graham Barr <gbarr [...] pobox.com>
I disagree that sum() should return 0 for an empty list. An empty list has no value. If you want 0 as the identity, then use sum(0, @list); This is documented in the POD If your algorithm requires that sum produce an identity of 0, then make sure that you always pass 0 as the first argument to prevent undef being returned $foo = sum 0, @values;
Subject: Re: [rt.cpan.org #76172] sum() should return 0
Date: Thu, 01 Nov 2012 15:32:58 +0100
To: bug-Scalar-List-Utils [...] rt.cpan.org
From: Lukas Mai <l.mai [...] web.de>
On 01.11.2012 15:08, Graham Barr via RT wrote: Show quoted text
> <URL: https://rt.cpan.org/Ticket/Display.html?id=76172 > > > I disagree that sum() should return 0 for an empty list.
Yes, but you're wrong. Show quoted text
> An empty list has no value.
An empty list contains zero values. The sum of zero values is 0 because 0 is the identity for +. Similarly, the product of zero values is 1 because 1 is the identity for *. This way it is always the case that sum($x, @xs) == $x + sum(@xs) and similarly, product($x, @xs) == $x * product(@xs). Sources: math, the Haskell standard library Show quoted text
> If you want 0 as the identity, then use sum(0, @list); This is documented in the POD > > > If your algorithm requires that sum produce an identity of 0, then make sure that you > always pass 0 as the first argument to prevent undef being returned > > $foo = sum 0, @values;
On Thu Nov 01 10:33:24 2012, l.mai@web.de wrote: Show quoted text
> On 01.11.2012 15:08, Graham Barr via RT wrote:
> > <URL: https://rt.cpan.org/Ticket/Display.html?id=76172 > > > > > I disagree that sum() should return 0 for an empty list.
> > Yes, but you're wrong.
I'm sorry but I'm with Lukas on this one. The sum of an empty list very much is zero. Rather, the result of folding an empty list by a binary operator is simply the identity value of that binary operation - so addition yields 0, multiplication yields 1. Show quoted text
> > An empty list has no value.
> > An empty list contains zero values. The sum of zero values is 0 > because > 0 is the identity for +. Similarly, the product of zero values is 1 > because 1 is the identity for *. > This way it is always the case that sum($x, @xs) == $x + sum(@xs) and > similarly, product($x, @xs) == $x * product(@xs). > > Sources: math, the Haskell standard library >
> > If you want 0 as the identity, then use sum(0, @list); This is
> documented in the POD
> > > > > > If your algorithm requires that sum produce an identity of 0,
> then make sure that you
> > always pass 0 as the first argument to prevent undef being
> returned
> > > > $foo = sum 0, @values;
>
However, it would be annoying to change the current behavior of sum() and product() now, because there may be a lot of old code relying on the undef-return from an empty list. I suggest a compromise solution. I will add functions use List::Util qw( sum0 product1 ); that yield 0 and 1 respectively when given an empty list. I will also look into seeing if it's possible to detect the version number that the module is used by, so we can apply similar hackery to use 5.010; to detect a version, and import properly. Given that the current version is 1.25, the next should be 1.26. Therefore I suggest that if we can manage it, the following behaviour should hold: use List::Util qw( sum sum0 ); sum () => undef sum0 () => 0 ust List::Util 1.26 qw( sum ); sum () => 0 This would be implemented by importing the &sum0 function as the sum symbol if the requested version is 1.26 or above, meaning that each user lexically gets to decide which sum behaviour they want. This would avoid breaking previous code, but allow a neater behaviour going forward. Does that please everyone? -- Paul Evans
Subject: Re: [rt.cpan.org #76172] sum() should return 0
Date: Fri, 2 Nov 2012 11:02:53 -0500
To: bug-Scalar-List-Utils [...] rt.cpan.org
From: Graham Barr <gbarr [...] pobox.com>
On Nov 2, 2012, at 10:15 , Paul Evans via RT wrote: Show quoted text
> > Does that please everyone?
No. I do not see any point in wasting namespace for sum0 when it can be clearly written as sum(0, @llist) as documented. And I am TOTALLY against changing sum() to return 0 for any future version. We have had this discussion in the past, MJD was one who raised it, and it was settled then that sum(0, @list) is a sufficient compromise to support those that want a zero identity and those that want to use undef to detect that sum(@list) was passed an empty list Graham.
CC: MAUKE [...] cpan.org
Subject: Re: [rt.cpan.org #76172] sum() should return 0
Date: Fri, 02 Nov 2012 21:57:30 +0100
To: bug-Scalar-List-Utils [...] rt.cpan.org
From: Lukas Mai <l.mai [...] web.de>
On 02.11.2012 17:03, Graham Barr via RT wrote: Show quoted text
> <URL: https://rt.cpan.org/Ticket/Display.html?id=76172 > > > > On Nov 2, 2012, at 10:15 , Paul Evans via RT wrote:
>> >> Does that please everyone?
Just having sum0 would please me a lot. The versioning trickery would just be icing on the cake. Show quoted text
> No. I do not see any point in wasting namespace for sum0 when it can be clearly written as sum(0, @llist) as documented.
The point is to have a mathematically correct sum function somewhere, preferably in List::Util. "It can be clearly written as sum(0, @list) as documented" is a bad excuse for providing a broken sum function by default, then expecting not just every user, but every calling site to remember to work around it by passing a dummy argument. It's also not composable: If a higher-order function takes a coderef where I'd normally pass \&sum (or \&sum0 with Paul's proposal), I have to remember to write sub { sum 0, @_ } instead. Every single time. I've literally never had a case where I've wanted the existing behavior of sum. Show quoted text
> And I am TOTALLY against changing sum() to return 0 for any future version.
OK, this is debatable. I fully understand not wanting to break existing users (though I have a hunch that at least some of them would actually be fixed by this change), but what's the argument against providing a different sum() to callers who explicitly request it? It leaves existing code working and it doesn't consume a new name. Show quoted text
> We have had this discussion in the past, MJD was one who raised it, and it was settled then that sum(0, @list) is a sufficient compromise to support those that want a zero identity and those that want to use undef to detect that sum(@list) was passed an empty list
How did you convince MJD? Because as far as I can tell, the matter has been unsettled again. I don't find sum(0, @list) to be a sufficient compromise because I'm skeptical that a compromise is needed in the first place. What is the use case for sum() returning undef? Assuming we did change sum, why is @list ? sum(@list) : undef not a sufficient compromise to get the other behavior? It more directly expresses the idea of wanting to detect an empty list and returning undef in that case. But that wasn't even the proposal. I just don't understand why you're so against changing anything in List::Util ever. Lukas
Subject: Re: [rt.cpan.org #76172] sum() should return 0
Date: Fri, 2 Nov 2012 16:03:20 -0500
To: bug-Scalar-List-Utils [...] rt.cpan.org
From: Graham Barr <gbarr [...] pobox.com>
On Nov 2, 2012, at 15:57 , Lukas Mai via RT wrote: Show quoted text
> >
>> We have had this discussion in the past, MJD was one who raised it, and it was settled then that sum(0, @list) is a sufficient compromise to support those that want a zero identity and those that want to use undef to detect that sum(@list) was passed an empty list
> > How did you convince MJD? Because as far as I can tell, the matter has > been unsettled again.
Just because YOU do not like it. Show quoted text
> I don't find sum(0, @list) to be a sufficient > compromise because I'm skeptical that a compromise is needed in the > first place. What is the use case for sum() returning undef?
Whats the use case for NULL in a relational database ? Show quoted text
> > Assuming we did change sum, why is @list ? sum(@list) : undef not a > sufficient compromise to get the other behavior?
Why is sum(0, @list) not a sufficient compromise ? The field of programming is not always 100% mathematically correct. Sometimes things are added to make things easier Show quoted text
> It more directly > expresses the idea of wanting to detect an empty list and returning > undef in that case.
To me, a programmer not a mathematician sum(0, @list) more clearly expresses that I want zero as a default return. Show quoted text
> > But that wasn't even the proposal. I just don't understand why you're so > against changing anything in List::Util ever.
I am not, but I am against reducing functionality. The point of common libraries is to make code as useful as possible to as many people as possible. Having sum() return 0 reduces that IMO. sum() is written is not broken as it does exactly what it is documented to do. It sounds like you just got surprised because you got an undef returned sometime. But thats documented, so IMO is correct. Graham.
Subject: Re: [rt.cpan.org #76172] sum() should return 0
Date: Fri, 02 Nov 2012 23:25:59 +0100
To: bug-Scalar-List-Utils [...] rt.cpan.org
From: Lukas Mai <l.mai [...] web.de>
On 02.11.2012 22:03, Graham Barr via RT wrote: Show quoted text
> <URL: https://rt.cpan.org/Ticket/Display.html?id=76172 > > > > On Nov 2, 2012, at 15:57 , Lukas Mai via RT wrote:
>> >>
>>> We have had this discussion in the past, MJD was one who raised it, and it was settled then that sum(0, @list) is a sufficient compromise to support those that want a zero identity and those that want to use undef to detect that sum(@list) was passed an empty list
>> >> How did you convince MJD? Because as far as I can tell, the matter has >> been unsettled again.
> > Just because YOU do not like it.
Yes. Is that not enough? But apparently it's not just me, because in this bug alone there are three people who think sum() should return 0 (as did MJD, apparently). Show quoted text
>> I don't find sum(0, @list) to be a sufficient >> compromise because I'm skeptical that a compromise is needed in the >> first place. What is the use case for sum() returning undef?
> > Whats the use case for NULL in a relational database ?
Representing unknown or indeterminate values in columns marked as allowing NULLs. For example, a table storing employees might have "birth date" or "phone number" fields with NULL entries when the values are not known. What does that have to do with sum? Show quoted text
>> >> Assuming we did change sum, why is @list ? sum(@list) : undef not a >> sufficient compromise to get the other behavior?
> > Why is sum(0, @list) not a sufficient compromise ?
Very funny. I gave a few reasons in the parts of my reply that you snipped. Show quoted text
> The field of programming is not always 100% mathematically correct. Sometimes things are added to make things easier
Yes, and now we want to do exactly that. It just so happens that the thing we want to add to make things easier is also 100% mathematically correct. Show quoted text
>> It more directly >> expresses the idea of wanting to detect an empty list and returning >> undef in that case.
> > To me, a programmer not a mathematician sum(0, @list) more clearly expresses that I want zero as a default return.
I'm not a mathematician either, and I think the name "sum" already implies that. If you wanted a different behavior, I'd suggest a name like "sum_with_default" (or "sum_from" to indicate that the 0 is the initial value of the accumulator). Show quoted text
>> >> But that wasn't even the proposal. I just don't understand why you're so >> against changing anything in List::Util ever.
> > I am not, but I am against reducing functionality.
I don't understand. The sum0 proposal adds functionality and removes nothing. Show quoted text
> The point of common libraries is to make code as useful as possible to as many people as possible. > Having sum() return 0 reduces that IMO.
Yes, but I'm skeptical of your opinion. How do you know how many people prefer what? Besides, "as useful as possible to as many people as possible" can't be our sole principle because blind application of it would lead us to an incoherent mess (I'm thinking of PHP here (http://php.net/gzgetss)). Show quoted text
> sum() is written is not broken as it does exactly what it is documented to do. It sounds like you > just got surprised because you got an undef returned sometime. But thats documented, so IMO is correct.
I don't find this argument convincing. For example, consider a sqrt that returns the string "nil" if the argument is 0. I would call that broken because "nil" is obviously not the square root of anything, and sqrt has no business returning a string anyway -- even if that behavior is clearly documented, and even if some users actually want that behavior: they can just write $x ? sqrt $x : "nil" instead, which is clearer to anyone familiar with what sqrt normally does, I think. To put it more bluntly: A bug doesn't cease to be a bug just because it's documented. (I don't think this actually describes the sum issue - I'm not accusing you of papering over a faulty implementation by documenting the problems or anything.) "not a bug - works as designed" is more convincing, but I'm arguing that in this case the design could be improved. Lukas
Personally, I would have made sum() return 0, following the principle of least surprise. Neverthless, the API has been set. I would strongly favor sum0 and product1 *without* import trickery. The mere presence of those functions will serve as extra documentation that regular sum and product might not give you what you want.
It looks like sum0 shipped with 1.26 last year. Perhaps this ticket should be closed...?
CC: MAUKE [...] cpan.org
Subject: Re: [rt.cpan.org #76172] sum() should return 0
Date: Mon, 8 Jul 2013 09:41:35 -0700
To: Peter Rabbitson via RT <bug-Scalar-List-Utils [...] rt.cpan.org>
From: Karen Etheridge <ether [...] cpan.org>
On Mon, Jul 08, 2013 at 02:38:35AM -0400, Peter Rabbitson via RT wrote: Show quoted text
> <URL: https://rt.cpan.org/Ticket/Display.html?id=76172 > > > It looks like sum0 shipped with 1.26 last year. Perhaps this ticket should be closed...?
It would appear it did, however it is not mentioned in the changelog -- could this be added please? https://metacpan.org/diff/release/PEVANS/Scalar-List-Utils-1.25/PEVANS/Scalar-List-Utils-1.26
On Fri Nov 02 16:57:49 2012, l.mai@web.de wrote: Show quoted text
> > We have had this discussion in the past, MJD was one who raised it, > > and it was settled then that sum(0, @list) is a sufficient compromise > > to support those that want a zero identity and those that want to use > > undef to detect that sum(@list) was passed an empty list
> > How did you convince MJD?
I have just become aware of this discussion, and I would like to place on the record that Graham certainly did not convince me of anything. My view is that he is clearly and entirely in the wrong here. But I have seen enough discussions of this type to know when there is no point in arguing, so I let it drop.