Challenge: Motivating examples for ...
Steven Schveighoffer
schveiguy at gmail.com
Sat Apr 25 14:15:39 UTC 2020
On 4/24/20 5:26 PM, Walter Bright wrote:
> On 4/22/2020 5:04 AM, Manu wrote:
>> [...]
>
> The examples in the DIP are, frankly, too trivial to make a case for the
> ... feature.
>
> So here's the challenge to everyone: a small (5?) collection of
> non-trivial motivating examples that show how it is done in D today, and
> how it is done with ...., and how much better the ... is.
I have a couple: std.meta.NoDuplicates, and std.meta.Filter
template NewFilter(alias pred, T...)
{
import std.meta : AliasSeq;
static if(T.length == 1)
{
static if(pred!T)
alias NewFilter = AliasSeq!(T);
else
alias NewFilter = AliasSeq!();
}
else
{
alias NewFilter = NewFilter!(pred, T)...;
}
}
Original implementation here:
https://github.com/dlang/phobos/blob/9844c34196c6f34743bfb4878d78cba804a57bf9/std/meta.d#L878-L898
Note that I've cut down the template instantiations from N *lg(N)
instantiations of Filter to N instantiations of NewFilter, and only one
level of recursion. Not only that, but...
If you have:
Filter!(Pred, SomeLongTuple);
NewFilter!(Pred, SomeLongTuple);
then
Filter!(Pred, SomeLongTuple[1 .. $]);
is going to produce a large amount of different instantiations (because
of the divide and conquer recursion). Mostly only the leaves will be reused.
But
NewFilter!(PRed, SomeLongTuple[1 .. $]);
will generate ONE more instantiation, because all the rest will have
been done from the first time.
Note that I have tested this in the proposed branch, with a few
workarounds for syntax (Manu is working on this). And it passes the same
unittests for Filter.
Now, for NoDuplicates, I have a personal interest in seeing this one be
fixed:
template staticIota(size_t N)
{
import std.meta : AliasSeq;
string buildIota()
{
import std.range : iota;
import std.format : format;
return format("alias staticIota = AliasSeq!(%(%d,%));", iota(N));
}
mixin(buildIota());
}
template NewNoDuplicates(T...)
{
import std.meta : AliasSeq;
template getAlias(size_t idx) {
alias list = T[0 .. idx];
alias item = T[idx];
import std.algorithm: canFind;
static if([__traits(isSame, list, item)...].canFind(true))
alias getAlias = AliasSeq!();
else
alias getAlias = AliasSeq!(T[idx]);
}
alias idxList = staticIota!(T.length)[1 .. $];
alias NewNoDuplicates = AliasSeq!(T[0], getAlias!(idxList)...);
}
Original implementation here:
https://github.com/dlang/phobos/blob/9844c34196c6f34743bfb4878d78cba804a57bf9/std/meta.d#L405-L505
(yes, that's 100 lines, but includes docs and unittests)
Comparison of instantiations is laughable. I'm instantiating one
template per element, plus the original NewNoDuplicates, vs. whatever
happens in std.meta (there are several helper templates).
I believe the complexity of the original filter is N * N * lg(N), where
as mine is N * N. If we had first-class type manipulation in CTFE, then
we could get it down to N lg(N) by sorting the list. Also, I can
probably avoid canFind and whatever it imports if I wanted to just
search with a simple loop function for any true values in a local CTFE
function.
I also tested this in the new branch, and it works, but again there are
some bugs in the implementation Manu is working on, so the compilable
version doesn't look as pretty.
Note, I think staticIota is going to be super-important if we get this
... (or whatever) change in, because you can do a lot of things now with
a tuple of indexes. The above is crude, and probably can be improved,
but note how we don't need all the vagaries of iota, because we can just
use ... expressions to make whatever sequence we need out of 0 .. N.
That's why I think something like AliasSeq!(0 .. N) handled by the
compiler would be tremendously useful.
-Steve
More information about the Digitalmars-d
mailing list