On 4/23/2020 10:51 PM, Manu wrote:
> Another reason I introduce `...` is for static fold.
> The follow-up to this DIP would make this expression work:
>
> `Tup + ...` -> `Tup[0] + Tup[1] + ... + Tup[$-1]`
I expect static foreach can handle that. But we can dig a little deeper. D
doesn't have a special syntax to sum the elements of an array, but it can use a
library function to do it. The next observation is that to sum the elements of a
tuple, all the tuple members need to be implicitly convertible to a single
arithmetic type. There is a way to do that:
[ Tup ]
and now the tuple is converted to an array literal, which can be summed the same
way array literals are currently summed. I.e. no need for extra syntax.
> For instance, up-thread it was noted that a static-fold algorithm may implement
> a find-type-in-tuple; it would look like this:
> `is(MyType == Types) || ...` <- evaluate `true` if MyType is present in
> Types with no template instantiation junk.
>
> So, the `...` is deliberately intended to being additional value.
is(MyType in Types)
could work. No need for ...
You can imagine that the expressions could be far more elaborate than that.
> Can you show how your suggestion applies to some more complex cases (not yet
> noted in the DIP).
>
> // controlled expansion:
> alias Tup = AliasSeq!(0, 1, 2);
> alias Tup2 = AliasSeq!(3, 4, 5);
> [ Tup, Tup2... ]... -> [ 0, 3, 4, 5 ], [ 1, 3, 4, 5 ], [ 2, 3, 4, 5 ]
[ Tup ~ [Tup2] ]
Though again, should be using arrays for this in the first place, not tuples.
> // template instantiations
> alias TTup = AliasSeq!(int, float, char);
> MyTemplate!(Tup, TTup.sizeof...)... -> MyTemplate!(0, 4, 4, 1), MyTemplate!(1,
> 4, 4, 1), MyTemplate!(2, 4, 4, 1)
Although we don't have UFCS for templates, this would be a point for that:
Tup.MyTemplate!(TTup.sizeof)
Otherwise it would suffer from the bottom-up semantic analysis problem I mention
further on.
I think this only satisfies a narrow set of possibilities.
There may be parallel expansion, and UFCS only handles one single UFCS argument, and also requires that it be the first argument.
> // replace staticMap
> alias staticMap(alias F, T...) = F!T...;
alias staticMap(alias F, T...) = F!T;
And if `F` accepts variadic arguments?
template F(Args...)
> // more controlled expansion, with template arg lists
> AliasSeq!(10, Tup, 20)... -> ( 10, 0, 20, 10, 1, 20, 10, 2, 20 )
What I don't like about this example is it can't be done with bottom-up
semantics, which is what D normally does. It relies on some top-down
modification for it, which is likely to cause all sorts of unexpected
difficulties. See the UFCS example above, where Tup is moved outside of the
argument list.
I'd like to know why you consider that troubling?
We were able to implement this DIP in a relatively small and completely self-contained block of code.
It's totally isolated, and easy to understand.
> AliasSeq!(10, Tup..., 20) -> ( 10, 0, 1, 2, 20 )
AliasSeq!(10, Tup, 20) -> ( 10, 0, 1, 2, 20 )
This is just normal D, but the first case (above) needs an expression.
> That said, with respect to these fold expressions, it would be ideal if they
> applied to arrays equally as I propose to tuples.
There's a lot of merit to the idea of arrays and tuples using a common syntax,
which is what I'm proposing.
I agree. I'm wondering if it might be the case that `...` is still a useful operator to make expansion explicit and unambiguous, and my definition is expanded to apply to arrays in addition to tuples, which would maintain that uniformity.