On Thu, Apr 23, 2020 at 2:50 PM Steven Schveighoffer via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
On 4/22/20 8:13 PM, Manu wrote:
> On Thu, Apr 23, 2020 at 2:10 AM Steven Schveighoffer via Digitalmars-d
> <digitalmars-d@puremagic.com <mailto:digitalmars-d@puremagic..com>> wrote:
>
>     On 4/22/20 11:17 AM, Manu wrote:
>      >
>      > I have thought about how to discuss this in the DIP; I describe the
>      > semantic, and what happens is what happens.
>      > This will work, and something will happen... when we implement
>      > TemplateInstance, we'll find out exactly what it is :P
>      > What I will do is show what such a nested tuple does when code
>     works in
>      > the DIP to instantiate TemplateInstances.
>      >
>      > It's basically the same thing as what you showed above with:
>      > Items[0].MemberTup, Items[1].MemberTup, ...
>      > In general, in D currently, nested tuples flatten. Evaluate from the
>      > leaf upwards. Your answer will materialise.
>
>     I think this is more complicated than the MemberTup thing. By inference
>     of the name, MemberTup is a tuple, but only defined in the context of
>     the expanded items. There aren't any tuples for the compiler to expand
>     in there.
>
>     A template that returns a tuple based on it's parameters is a tuple
>     with
>     or without expansion.
>
>     F!(F!t)) is valid. It's going to return int, char, int, char, int,
>     char,
>     int, char
>
>     F!(F!t))... what does this do?
>
> I expect it will do this:
>
> F!(F!t)... =>
>
> expand for `t` (at leaf of tree):
> F!( (F!t[0], F!t[1]) )  ~= F!( (F!int, F!char) )  =>

OK, that is what I thought too (that is the most useful), but this needs
to be explicit in the DIP.

Remember that templates can also be tuples too, so when it says " for
any tuples present in the expression tree", it reads ambiguous.

I will bring up again something like this, which someone might expect to
work:

alias G(T) = const(T);

alias F(T) = AliasSeq!(T, T);

alias f = F!(int);
G!(f)...; // seems cool to me
G!(F!int)...; // compiler error or works?
G!(AliasSeq!(int, char))...; // error or works?

> Spec does not say it will NOW evaluate the template and operate on the
> result, it deals with the expression as stated.

I'm not expecting multiple expansions, but one has to remember that D is
full of templates that create tuples, so the DIP has to say at what
point "these tuples are generated and considered before the expansion"
and "these are not". It seems to me you are saying only tuples that
exist BEFORE the expression are considered. Something like that should
be in the DIP, with appropriate examples.

Yes, these are very good points. Thanks for spelling this out clearly.

In the event you want the behaviour where the template resolution is expanded, I reckon people would expect this is the natural solution:
    alias Tup = TupleFromTemplate!(Instantiation, Args);
    (Tup + expr)...

In this expression, `Tup` would expand, because the instantiation that created the tuple is not involved in the expression being expanded.
I have to double-check, but I expect that's precisely how the code works naturally with no intervention. AliasSeq!() itself depends on this behaviour to work right now in our unittests.

So, if you find yourself in a situation where you want to expand a tuple into a template instantiation, and that instantiation resolves to a tuple which you want to further expand, you just need to break it into 2 lines. That will also have the nice side-effect of being much clearer to read.

> That's the expansion I would expect from that expression. So, I guess
> the point you want to determine is that *evaluating* templates is NOT
> part of tuple expansion.

A good way to say it, but still needs examples in the DIP to clarify. To
elaborate, you might say:

"expansion is performed only on tuples represented by symbols in the
expression. All template instantiations that generate tuples are
performed after expansion is finished."

Yes, this reads well, thanks again. I was struggling to imagine simple language to describe this behaviour.

> I think that expansion is actually reasonable and 'easy' to understand.
> There's nothing unexpected about application of the stated rules.
> Of course, I would suggest not writing code like this, unless it's
> really clear to the reader what your intent was. There's a
> million-and-one ways to write obscure code that does something, but
> doesn't really help the reader along the way; this expression is one
> such thing.

It's easy to understand, but it's also easy to expect the compiler to
understand what you were thinking when you wrote:

foo!(AliasSeq!(int, char))...

instead of the (required) long form:

alias args = AliasSeq!(int, char);
foo!(args)...

proper tuples would make this much less painful...

You're exactly correct, the first instantiation needs to be broken out to a separate line.
Exactly. I hope this feature might motivate renewed interest in first-class tuples, and that would improve this situation.