So... add maxCount and maxPos?

Ivan Kazmenko via Digitalmars-d digitalmars-d at puremagic.com
Wed Jan 20 18:36:05 PST 2016


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.



More information about the Digitalmars-d mailing list