Andrei Alexandrescu:
http://www.infoq.com/presentations/Generic-Programming-Galore-Using-D
It was a quite good talk.
Slide 13: very good, I am asking for min([1, 3, 5)) for a lot of
time :-) (http://d.puremagic.com/issues/show_bug.cgi?id=4705 ).
I hope to see those new min/max/argMin/argMax functions in Phobos.
I'd also like the mins()/maxs() functions, as explained in Issue
4705, their need is common. I have added some use cases there.
(But your code doesn't work with opApply, so it doesn't work with
everything as the slide says).
------------------------------
Slide 15:
auto m = argmin!((x) { return x.length;})(s);
As deadalnix notes, that was a good place to show the new D
lambda template syntax and UCFS:
auto m = s.argmin!(x => x.length)();
But it also shows why Python (unlike Ruby) uses a free function
for length (that calls a __len__ standard method on objects and
built-ins), it allows you to write that code with no need of
lambdas (it also shows why Python named arguments are nice):
m = min(s, key=len)
So in D to avoid defining a lambda I sometimes use walkLength as
free function (but I have to keep in mind it gives different
results on narrow strings!):
auto m = s.argmin!walkLength();
And maybe "argMin" name is more fitting in D than "argmin".
----------------------------
[Attention, uncooked ideas ahead]
Creating a good min() is not so easy. When I did create the
dlibs1 in D1 I didn't know this, so I thought of myself as a not
so good enough programmer for finding it not so easy to create
the min/max functions :-)
At about 40.00 of your talk there was an interesting question and
answer. D sees 255 on default as an integer literal:
auto x = 255;
static assert(is(typeof(x) == int));
But D also accepts this, because D knows this is a valid ubyte
literal too, it fits in the ubyte interval:
ubyte x = 255;
The D compiler even accepts this with no errros or warnings,
requiring no cast to assign z:
void main(string[] args) {
uint x;
ubyte y = cast(ubyte)args.length;
ubyte z = x % y;
}
(A bug on this:
http://d.puremagic.com/issues/show_bug.cgi?id=7834 ).
So another possible desiderata for a 'dream' min() function is
this to compile, with no need of a cast in the user code:
void main(string[] args) {
ubyte u = min(args.length, 255);
}
To allow this I think D needs some more static
introspection/skills. The template of the min() function needs to
be informed not just that the second argument is of type int, but
also that it's a literal (or value known at compile time witn no
need of running compile-time code to compute it, this is a
requirement of the way D CTFE works), and it also fits in an
ubyte range.
The result of that min() is of type size_t, so this is true (so
the min of an unsigned short and an unsigned int is an unsigned
int type still. Types and their ranges are orthogonal things):
auto u = min(args.length, 255);
static assert(is(typeof(u) == size_t));
But this also compiles because the compiler knows that despite
the result of that min() call is a size_t the compile-time range
of that size_t value fits inside a ubyte range too (just like for
the built-in literal 255 that the compiler knows has a range that
fits in an ubyte too):
ubyte u = min(args.length, 255);
So I think this kind of code needs a way to tell statically:
- The actual statically known range of a compile-time known
integral value.
- It also needs the ability to _assign_ a statically known range
to an integer value. To make things simpler the compiler is not
required to prove that this is a correct assignment, it accepts
it with an act of faith.
Opionally I'd also like a way to tell, from inside the template:
- If a template argument is a literal (or it's a value known
statically with no need to run compile-time code);
- If the result of the function is assigned to a variable or not
(if this information is used, then the template instantiates
itself again in two variants, according to the boolean result of
this query)).
I think a first step is to have something like this, to call from
user code the interval analysis engine inside the D compiler. I
think this just is just a way to expose to user code stuff
already existing inside the compiler, so I think this requires
only a small amount of compiler code to be added (I it's better
for the result to be an interval closed on the right, unlike most
other intervals in D):
uint x = ...;
__traits(interval, x & ubyte.max) ===> TypeTuple!(0, 255)
That alone is not enough to implement that "dream min". Because
if you do this:
void foo(T)(T x) {
writeln([__traits(interval, x)]);
}
void main() {
foo(255);
}
I think it prints this, because the result of interval analysis
gets lot when the expression ends or at function call point:
[-2147483648, 2147483647]
Bye,
bearophile