So... add maxCount and maxPos?
This is one of those cases in which we were pedantically right to not add them, but their equivalents look like crap. https://github.com/D-Programming-Language/phobos/pull/3942 Andrei
Re: So... add maxCount and maxPos?
On Wed, Jan 20, 2016 at 12:16:00PM -0500, Andrei Alexandrescu via Digitalmars-d wrote: > This is one of those cases in which we were pedantically right to not > add them, but their equivalents look like crap. > > https://github.com/D-Programming-Language/phobos/pull/3942 [...] I don't like this. I'd much rather we rename those functions to be something more generic. After all, minPos is a horrible name when the predicate has nothing to do with minimum values. What about extremumPos? (Though that's rather ugly to type.) T -- People demand freedom of speech to make up for the freedom of thought which they avoid. -- Soren Aabye Kierkegaard (1813-1855)
Re: So... add maxCount and maxPos?
On 01/20/2016 12:29 PM, H. S. Teoh via Digitalmars-d wrote: On Wed, Jan 20, 2016 at 12:16:00PM -0500, Andrei Alexandrescu via Digitalmars-d wrote: This is one of those cases in which we were pedantically right to not add them, but their equivalents look like crap. https://github.com/D-Programming-Language/phobos/pull/3942 [...] I don't like this. I'd much rather we rename those functions to be something more generic. After all, minPos is a horrible name when the predicate has nothing to do with minimum values. What about extremumPos? (Though that's rather ugly to type.) extremumPos has been on my wish list for a while now, but (a) we're stuck with minPos anyway, (b) extremumPos sounds elitist. -- Andrei
Re: So... add maxCount and maxPos?
On Wed, Jan 20, 2016 at 02:30:10PM -0500, Andrei Alexandrescu via Digitalmars-d wrote: > On 01/20/2016 12:29 PM, H. S. Teoh via Digitalmars-d wrote: > >On Wed, Jan 20, 2016 at 12:16:00PM -0500, Andrei Alexandrescu via > >Digitalmars-d wrote: > >>This is one of those cases in which we were pedantically right to > >>not add them, but their equivalents look like crap. > >> > >>https://github.com/D-Programming-Language/phobos/pull/3942 > >[...] > > > >I don't like this. I'd much rather we rename those functions to be > >something more generic. After all, minPos is a horrible name when > >the predicate has nothing to do with minimum values. What about > >extremumPos? (Though that's rather ugly to type.) > > extremumPos has been on my wish list for a while now, but (a) we're > stuck with minPos anyway, (b) extremumPos sounds elitist. -- Andrei If renaming is out of the question, then I suppose maxPos/maxCount would be the next less evil. :-P If we ever get to D3, this would be one of the things that should be changed... but until then, I guess we can live with maxPos/maxCount. T -- Error: Keyboard not attached. Press F1 to continue. -- Yoon Ha Lee, CONLANG
Re: So... add maxCount and maxPos?
On 01/20/2016 06:29 PM, H. S. Teoh via Digitalmars-d wrote: On Wed, Jan 20, 2016 at 12:16:00PM -0500, Andrei Alexandrescu via Digitalmars-d wrote: This is one of those cases in which we were pedantically right to not add them, but their equivalents look like crap. https://github.com/D-Programming-Language/phobos/pull/3942 [...] I don't like this. I'd much rather we rename those functions to be something more generic. After all, minPos is a horrible name when the predicate has nothing to do with minimum values. The predicate always describes an order relative to which to find a minimum.
Re: So... add maxCount and maxPos?
On Wednesday, 20 January 2016 at 17:16:00 UTC, Andrei Alexandrescu wrote: This is one of those cases in which we were pedantically right to not add them, but their equivalents look like crap. https://github.com/D-Programming-Language/phobos/pull/3942 As it seems related, let me share my personal experience with minPos. Most of the time, I want one of the two things related to an extremum. 1. The minimum or maximum element itself. I write it as a.minPos.front. That's almost fine, but maybe there is a more expressive way? 2. The index of minimum or maximum element, mostly using plain array as a range. I write "a.length - a.minPos.length", and it looks completely unintuitive. Additionally, when compiling to 64 bits, I usually still want an int to use with other ints around (longs are overkill most of the time), and the cast adds more clobber. Again, is there a better way to express that? 3. Other uses: I've yet to see the need. In a random collection of my D code, the number of occurrences of cases 1:2:3 is 6:4:0. I've got used to "minPos !(q{a > b})" instead of "maxPos", but a maxPos alias would of course make things a bit more clear. Don't know how much of a justification that is. Ivan Kazmenko.
Re: So... add maxCount and maxPos?
On 01/20/2016 06:16 PM, Andrei Alexandrescu wrote: This is one of those cases in which we were pedantically right to not add them, but their equivalents look like crap. https://github.com/D-Programming-Language/phobos/pull/3942 Andrei One reason why dual notions usually both receive names is that naming one of them but not the other is arbitrary and confusing. (Reversing all arrows in the respective category is often just not a very natural operation, even if it has a computational interpretation.) Languages don't just leave out one of && or || either.
Re: So... add maxCount and maxPos?
On 01/20/2016 04:22 PM, Ivan Kazmenko wrote: On Wednesday, 20 January 2016 at 17:16:00 UTC, Andrei Alexandrescu wrote: This is one of those cases in which we were pedantically right to not add them, but their equivalents look like crap. https://github.com/D-Programming-Language/phobos/pull/3942 As it seems related, let me share my personal experience with minPos. Most of the time, I want one of the two things related to an extremum. 1. The minimum or maximum element itself. I write it as a.minPos.front. That's almost fine, but maybe there is a more expressive way? Sadly, no. I'm very willing to add an overload of min and max for one argument (which fortunately does not compile currently) to compute these over a range. In fact literally today I wrote r.min and was surprised it didn't work. Would you want to embark on that? Code, docs, unittests, the works. 2. The index of minimum or maximum element, mostly using plain array as a range. I write "a.length - a.minPos.length", and it looks completely unintuitive. Additionally, when compiling to 64 bits, I usually still want an int to use with other ints around (longs are overkill most of the time), and the cast adds more clobber. Again, is there a better way to express that? No better way currently. We could add (min|max)Index but I like (min|max)Pos quite a bit. They offer more flexibility for non-random access ranges. For random access ranges you should soon be able to write a.before(a.minPos).length, for a different kind of unintuitiveness :o). Andrei
Re: So... add maxCount and maxPos?
On Thursday, 21 January 2016 at 01:11:19 UTC, Andrei Alexandrescu wrote: On 01/20/2016 04:22 PM, Ivan Kazmenko wrote: 1. The minimum or maximum element itself. I write it as a.minPos.front. That's almost fine, but maybe there is a more expressive way? Sadly, no. I'm very willing to add an overload of min and max for one argument (which fortunately does not compile currently) to compute these over a range. In fact literally today I wrote r.min and was surprised it didn't work. Would you want to embark on that? Code, docs, unittests, the works. Hmm. I was at first frustrated by not having min(Range). But I looked for a reason it does not yet exist, and I found one. Say we define min of one argument, which is a range, to be the minimum value of that range. Now, what if we unpack tuples as arguments for min, and some tuple happens to have one element, which is a range? Currently, this immediately triggers a compile error. On the other hand, if we add the one-argument range version, it will silently produce a value of another type. As all of this may happen only at compile time, and the type system is rather strict, hopefully this will hit a compile error down the road, but even then, the actual cause will be harder to find. An example: - import std.algorithm, std.range, std.stdio, std.typecons; alias minBinary = (x, y) => x < y ? x : y; auto min (Args...) (Args args) if (args.length > 1) { return args.only.reduce!minBinary; } auto min (T) (T [] arr) { return arr.reduce!minBinary; } void main () { writeln (min (3, 1, 2)); // 1 writeln (min ([3, 1, 2])); // 1 writeln (min (tuple ([5, 6], [1, 2], [3, 4]).expand)); // [1, 2] writeln (min (tuple ([3, 1, 2]).expand)); // 1, huh? } - So, min(Range) + tuple expansion = problem. An alternative would be to define min(one argument) to just be that argument. That would be consistent with what we have now, but violates the principle of least astonishment for newcomers: why would min ([3, 1, 2]) return [3, 1, 2] and not 1? Currently, it just does not compile. So, I convinced myself that the current situation is the lesser evil. Currently, the second and fourth writeln in the example just don't compile if we comment out our min functions. 2. The index of minimum or maximum element, mostly using plain array as a range. I write "a.length - a.minPos.length", and it looks completely unintuitive. Additionally, when compiling to 64 bits, I usually still want an int to use with other ints around (longs are overkill most of the time), and the cast adds more clobber. Again, is there a better way to express that? No better way currently. We could add (min|max)Index but I like (min|max)Pos quite a bit. They offer more flexibility for non-random access ranges. For random access ranges you should soon be able to write a.before(a.minPos).length, for a different kind of unintuitiveness :o). Well, this at least reads a bit like English: take the part of "a" before minimum position in "a" and calculate its length. The downside is two uses of "a" which are certain to put more burden on the optimizer. The current "whole length minus length after minimum" is a negative wording, which adds to perceived complexity every time it is used. Ivan Kazmenko.
Re: So... add maxCount and maxPos?
On 01/20/2016 09:36 PM, Ivan Kazmenko wrote: So, min(Range) + tuple expansion = problem. OK, convinced. There's of course the option of (min|max)Element. -- Andrei
Re: So... add maxCount and maxPos?
On Thursday, 21 January 2016 at 01:11:19 UTC, Andrei Alexandrescu wrote: On 01/20/2016 04:22 PM, Ivan Kazmenko wrote: 2. The index of minimum or maximum element, mostly using plain array as a range. I write "a.length - a.minPos.length", and it looks completely unintuitive. Additionally, when compiling to 64 bits, I usually still want an int to use with other ints around (longs are overkill most of the time), and the cast adds more clobber. Again, is there a better way to express that? No better way currently. We could add (min|max)Index but I like (min|max)Pos quite a bit. They offer more flexibility for non-random access ranges. But (min|max)(Index|Key) offer different type of flexibility as those make sense for associative containers.
Re: So... add maxCount and maxPos?
On Thursday, 21 January 2016 at 02:36:05 UTC, Ivan Kazmenko wrote: An alternative would be to define min(one argument) to just be that argument. That would be consistent with what we have now, but violates the principle of least astonishment for newcomers: why would min ([3, 1, 2]) return [3, 1, 2] and not 1? Currently, it just does not compile. As a newcomer to the language, and as a reader of https://dlang.org/phobos/std_algorithm_comparison.html#min which states "Iterates the passed arguments and returns the minimum value." my intuitive understanding would be that yes of course min(x) returns x. However the above could of course also be reworded as "Iterates the passed list of arguments and returns the minimum value." to be even more clear about it NOT iterating individual arguments but the argument list as a whole :-) If I were to be a newcomer to programming in general this might be confusing, though. However, it's certainly consistent and easy to wrap your head around and also what I would have expected it to do the first time I came across the function.
Re: So... add maxCount and maxPos?
On Thursday, 21 January 2016 at 12:17:26 UTC, default0 wrote: On Thursday, 21 January 2016 at 02:36:05 UTC, Ivan Kazmenko wrote: An alternative would be to define min(one argument) to just be that argument. That would be consistent with what we have now, but violates the principle of least astonishment for newcomers: why would min ([3, 1, 2]) return [3, 1, 2] and not 1? Currently, it just does not compile. As a newcomer to the language, and as a reader of https://dlang.org/phobos/std_algorithm_comparison.html#min which states "Iterates the passed arguments and returns the minimum value." my intuitive understanding would be that yes of course min(x) returns x. However the above could of course also be reworded as "Iterates the passed list of arguments and returns the minimum value." to be even more clear about it NOT iterating individual arguments but the argument list as a whole :-) If I were to be a newcomer to programming in general this might be confusing, though. However, it's certainly consistent and easy to wrap your head around and also what I would have expected it to do the first time I came across the function. Still, looks like Java, C# and Python have min work this way: given a single argument which is a collection, it returns the minimum in that collection, not the collection itself. A Python example: min ([1]) // 1 min ([2, 1]) // 1 min ((([1, 2], [2, 3]))) // [1, 2] min ((([1, 2]))) // 1 min ((([1, 2],),)) // ([1, 2],) In Python, the what happens is also tricky: def g(): return (1, 2) // tuple of two values g() // (1, 2) min (g()) // 1 from tuple min (*g()) // 1 from expanded tuple def f(): return (1,) // tuple of a single value f() // (1,) min (f()) // 1 min (*f()) // error, cannot expand
Re: So... add maxCount and maxPos?
On Wednesday, 20 January 2016 at 17:29:28 UTC, H. S. Teoh wrote: On Wed, Jan 20, 2016 at 12:16:00PM -0500, Andrei Alexandrescu via Digitalmars-d wrote: This is one of those cases in which we were pedantically right to not add them, but their equivalents look like crap. I don't like this. I'd much rather we rename those functions to be something more generic. After all, minPos is a horrible name when the predicate has nothing to do with minimum values. What about extremumPos? (Though that's rather ugly to type.) maxCount sounds too much like it's suppose to be a function in SQL querying, and minCount... ugg... now I wonder what in the world we're talking about. From algorithm.d: int[] a = [ 2, 3, 4, 1, 2, 4, 1, 1, 2 ]; // Minimum is 1 and occurs 3 times assert(a.minCount == tuple(1, 3)); // Maximum is 4 and occurs 2 times assert(a.maxCount == tuple(4, 2)); // Minimum is 1 and first occurs in position 3 assert(a.minPos == [ 1, 2, 4, 1, 1, 2 ]); // Maximum is 4 and first occurs in position 2 assert(a.maxPos == [ 4, 1, 2, 4, 1, 1, 2 ]); These unittests make it completely clear what it wants to do. I'd almost say lowestCount and highestCount would almost be better, but i am not sure. or just unitCount? Or countOf and posOf? which make a lot more sense when instantiated: So a.countOf!("a < b")? I'm seriously behind on all of this.
Re: So... add maxCount and maxPos?
On 01/21/2016 08:42 AM, Era Scarecrow wrote: I'd almost say lowestCount and highestCount would almost be better, but i am not sure. minCount is already a given. -- Andrei
Re: So... add maxCount and maxPos?
On Thursday, 21 January 2016 at 14:04:58 UTC, Andrei Alexandrescu wrote: On 01/21/2016 08:42 AM, Era Scarecrow wrote: I'd almost say lowestCount and highestCount would almost be better, but i am not sure. minCount is already a given. -- Andrei countMost!less and posMost!less
Re: So... add maxCount and maxPos?
On Thursday, 21 January 2016 at 14:04:58 UTC, Andrei Alexandrescu wrote: On 01/21/2016 08:42 AM, Era Scarecrow wrote: I'd almost say lowestCount and highestCount would almost be better, but I am not sure. minCount is already a given. -- Andrei I have a slight problem where I'm not already familiar with most of the standard library functions (D, libc, etc) that are usually available. This usually means I have a naive approach and/or naming convention to what's already been in place 15+ years. Of course when I do take the time to go through the libraries and documentation I'll say 'oohhh that's cool!'; But because I'm not actively using it I'll promptly forget it :(