November 03, 2020 Re: Discussion Thread: DIP 1037--Add Unary Operator ...--Community Review Round 1 | ||||
---|---|---|---|---|
| ||||
Posted in reply to Q. Schroll Attachments:
| On Tue, Nov 3, 2020 at 8:55 AM Q. Schroll via Digitalmars-d < digitalmars-d@puremagic.com> wrote:
> On Wednesday, 28 October 2020 at 10:57:37 UTC, Jacob Carlborg wrote:
> > On Tuesday, 27 October 2020 at 10:54:07 UTC, Mike Parker wrote:
> >> This is the discussion thread for the first round of Community Review of DIP 1037, "Add Unary Operator ...":
> >>
> >>
> https://github.com/dlang/DIPs/blob/ba81eec84ddf0aeeb2cb652743b292455ec8c62a/DIPs/DIP1037.md
> >
> > Is there a risk of causing some form of ambiguity with variadic functions?
>
> No, because the DIP does not propose anything with types. In the DIP, it says "expression" everywhere; it's for use in expressions, not types. It doesn't forbid types to occur in the tuple for good reasons, simply because types can very well occur in expression contexts, but the result will always be an expression. If you want a drastic example how far reaching expression vs type context is: given a type T, T[] can mean: slice of T or T.opIndex. If T defines static opIndex, in an expression context, T[] will mean T.opIndex, and in a type context, it will mean slice of T (kinda obvious). Let Ts := (T1, T2); if you'd do (Ts[]).sizeof... --- because ... is only valid in an expression context --- it *must* lower to (T1.opIndex.sizeof, T2.opIndex.sizeof). By the grammar given in the DIP, the ... do not have anything to do with the type expression stuff.
>
> The example given in the DIP with `cast(Types)Values...` might work by accident because types are also expressions. By the grammar provided, `cast(Types[])Values...` could never work as intended! The example
>
> alias staticMap(alias F, T...) = F!T...;
>
> cannot work. By the grammar provided, F!T... must be an expression, not a "type expression", but alias requires a type context as its target. (I.e. alias x = 5; doesn't work; alias x = y + 1; doesn't work either because the right-hand sides aren't types.)
>
> In the Feedback Thread, I commented that it would be great to have the proposed operator apply to type contexts as well [1]. Didn't get an answer, but do hope I get one eventually.
>
> Problem is, as you started digging: For a class C (and classes only, not structs or anything else), the parameter definition C... is already defined [2, see "4. For class objects"]. For example,
>
> class C { this(int, string) { } }
> void foo(C...) { }
> void main() { foo(1, "abc"); }
>
> compiles [3]. So if C is the last entry in a type-only AliasSeq that is used in a parameter list, notations clash. Currently valid [4] code like
>
> import std.meta : AliasSeq;
> class C { this(int, string) { } }
> alias Types = AliasSeq!(int, string, C);
> void foo(Types args...) { }
> void main() { foo(1, "abc", 2, "xyz"); }
>
> would no longer compile, since `Types...` would be the literal same as using `Types` without dots.
>
> [1]
> https://forum.dlang.org/post/fogbdhcdeukiucbxxxns@forum.dlang.org
> [2]
> https://dlang.org/spec/function.html#typesafe_variadic_functions
> [3] https://run.dlang.io/is/GmgAaG
> [4] https://run.dlang.io/is/DeGZF7
Thank you for this analysis. This is useful. I'll confirm the DIP's spec
and implementation against your points.
It might be that the implementation works by happen-stance, or perhaps my
stated grammar change wasn't accurate.
It's very hard to express a grammar change in a DIP like this, since D
doesn't have a grammar as such; it's just an implementation, and
reverse-engineering a grammar from the implementation is imprecise. Perhaps
my implementation implies additional grammar changes that I didn't notice.
|
November 03, 2020 Re: Discussion Thread: DIP 1037--Add Unary Operator ...--Community Review Round 1 | ||||
---|---|---|---|---|
| ||||
Posted in reply to Manu | On Tuesday, 3 November 2020 at 02:30:58 UTC, Manu wrote:
> Perhaps my implementation implies additional grammar changes that I didn't notice.
It does, if it should work on types. In the easiest case, if you want
alias X(Args...) = (T!Args)...;
to work like
alias X(Args...) = staticMap!(T, Args);
you cannot do that by merely adding a new PostfixExpression. It is necessary to add `...` to BasicType2X, i.e.
BasicType2X:
*
[ ]
[ AssignExpression ]
[ AssignExpression .. AssignExpression ]
+ ...
[ Type ]
but I may have overlooked something and it might not suffice. The grammar concerning "type expressions" is convoluted and has some stuff going on in AltDeclarator where I'm not entirely sure it can be ignored.
|
November 03, 2020 Re: Discussion Thread: DIP 1037--Add Unary Operator ...--Community Review Round 1 | ||||
---|---|---|---|---|
| ||||
Posted in reply to Manu | On Tuesday, 3 November 2020 at 02:30:58 UTC, Manu wrote:
> It might be that the implementation works by happen-stance, or perhaps my
> stated grammar change wasn't accurate.
Probably you didn't care that much about the formal grammar and wanted to get the implementation done. To be honest, I thought about writing a similar DIP, but chickened out because the "pushing down" of the expansion looked complicated to me. If that gets accepted (after the rough edges got rounded), it will make static indexing even more wanting.
|
November 03, 2020 Re: Discussion Thread: DIP 1037--Add Unary Operator ...--Community Review Round 1 | ||||
---|---|---|---|---|
| ||||
Posted in reply to Manu | On 11/2/20 9:30 PM, Manu wrote:
> It's very hard to express a grammar change in a DIP like this, since D doesn't have a grammar as such; it's just an implementation, and reverse-engineering a grammar from the implementation is imprecise. Perhaps my implementation implies additional grammar changes that I didn't notice.
I thought the grammar is fairly complete, no? It's the semantics that's poorly defined.
|
November 03, 2020 Re: Discussion Thread: DIP 1037--Add Unary Operator ...--Community Review Round 1 | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrei Alexandrescu Attachments:
| On Tue, Nov 3, 2020 at 4:05 PM Andrei Alexandrescu via Digitalmars-d < digitalmars-d@puremagic.com> wrote:
> On 11/2/20 9:30 PM, Manu wrote:
> > It's very hard to express a grammar change in a DIP like this, since D doesn't have a grammar as such; it's just an implementation, and reverse-engineering a grammar from the implementation is imprecise. Perhaps my implementation implies additional grammar changes that I didn't notice.
>
> I thought the grammar is fairly complete, no? It's the semantics that's poorly defined.
>
It may be complete, but it's difficult to relate to the code, and when
making changes to DMD, it's easy to make changes and not clearly see how it
might have affected the grammar shown in the spec.
It's just that someone reverse-engineered an approx grammar from the
implementation. DMD doesn't have a formal grammar; it's implementation
defined.
|
November 03, 2020 Re: Discussion Thread: DIP 1037--Add Unary Operator ...--Community Review Round 1 | ||||
---|---|---|---|---|
| ||||
Posted in reply to Q. Schroll Attachments:
| On Tue, Nov 3, 2020 at 1:15 PM Q. Schroll via Digitalmars-d < digitalmars-d@puremagic.com> wrote:
> On Tuesday, 3 November 2020 at 02:30:58 UTC, Manu wrote:
> > Perhaps my implementation implies additional grammar changes that I didn't notice.
>
> It does, if it should work on types. In the easiest case, if you want
>
> alias X(Args...) = (T!Args)...;
>
> to work like
>
> alias X(Args...) = staticMap!(T, Args);
>
> you cannot do that by merely adding a new PostfixExpression. It is necessary to add `...` to BasicType2X, i.e.
>
> BasicType2X:
> *
> [ ]
> [ AssignExpression ]
> [ AssignExpression .. AssignExpression ]
> + ...
> [ Type ]
>
> but I may have overlooked something and it might not suffice. The grammar concerning "type expressions" is convoluted and has some stuff going on in AltDeclarator where I'm not entirely sure it can be ignored.
>
You're right, and a change like that does exist in my implementation
somewhere; I just need to look again at the implementation to spot it and
confirm it in the grammar changes.
I wondered if I overlooked some cases too; but the unit tests are fairly
comprehensive and exercise all the constructs that we ever imagined could
be useful.
There's a grammar change that supports:
alias staticMap(F, Args...) = F!Args...;
And also:
MyTemplate!(expr...) <-- appearance in template parameter lists
It's also deliberate and necessary that the grammar is NOT modified such
that `...` could be accepted in argument list definitions, because that's
where ambiguity can occur.
If you want to use `...` in an argument list, you can make an alias on the
preceding line:
alias MappedArgs = TupExpr...;
void fun(MappedArgs args) { ... } <-- `...` can not appear in a
parameter list, so hoist it to the line above
I actually really like this incidental restriction; it makes declarations clearer.
|
November 03, 2020 Re: Discussion Thread: DIP 1037--Add Unary Operator ...--Community Review Round 1 | ||||
---|---|---|---|---|
| ||||
Posted in reply to Manu | On 11/3/20 2:05 AM, Manu wrote:
> MyTemplate!(expr...) <-- appearance in template parameter lists
By the way in C++ the expansion applies to so-called patterns, not expressions:
pattern...
The pattern allowed depends on the context in which it's seen. E.g., if it's in a function call arguments, it's the largest expression to the left of "...".
The difficulty in D is that it's not always clear if something is meant to be an expression or a type. Consider:
template X(T...) { }
X!(pattern...);
It's unclear whether the pattern is meant to expand into types or expressions. I don't know whether there's a case in D where that could create a confusion.
|
November 03, 2020 Re: Discussion Thread: DIP 1037--Add Unary Operator ...--Community Review Round 1 | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrei Alexandrescu | On Tuesday, 3 November 2020 at 13:46:20 UTC, Andrei Alexandrescu wrote:
> On 11/3/20 2:05 AM, Manu wrote:
>> MyTemplate!(expr...) <-- appearance in template parameter lists
>
> By the way in C++ the expansion applies to so-called patterns, not expressions:
>
> pattern...
>
> The pattern allowed depends on the context in which it's seen. E.g., if it's in a function call arguments, it's the largest expression to the left of "...".
>
> The difficulty in D is that it's not always clear if something is meant to be an expression or a type. Consider:
>
> template X(T...) { }
> X!(pattern...);
>
> It's unclear whether the pattern is meant to expand into types or expressions. I don't know whether there's a case in D where that could create a confusion.
A Type in practice is just an expression.
Consider:
alias A(T) = T;
pragma(msg, A!int); // prints int;
pragma(msg, !A!int); // prints false.
If you can use ! on something, it's an expression.
|
November 03, 2020 Re: Discussion Thread: DIP 1037--Add Unary Operator ...--Community Review Round 1 | ||||
---|---|---|---|---|
| ||||
Posted in reply to Stefan Koch | On Tuesday, 3 November 2020 at 16:34:39 UTC, Stefan Koch wrote:
> A Type in practice is just an expression.
>
> Consider:
>
> alias A(T) = T;
Is it though? It would be nice if alias could bind to expressions, but it clearly can't.
alias T = 42; // fails
enum __tmp = 42;
alias T = __tmp; // ok
|
November 04, 2020 Re: Discussion Thread: DIP 1037--Add Unary Operator ...--Community Review Round 1 | ||||
---|---|---|---|---|
| ||||
Posted in reply to Ola Fosheim Grøstad | On Tuesday, 3 November 2020 at 17:23:23 UTC, Ola Fosheim Grøstad wrote:
> On Tuesday, 3 November 2020 at 16:34:39 UTC, Stefan Koch wrote:
>> A Type in practice is just an expression.
>>
>> Consider:
>>
>> alias A(T) = T;
>
> Is it though? It would be nice if alias could bind to expressions, but it clearly can't.
>
> alias T = 42; // fails
>
> enum __tmp = 42;
> alias T = __tmp; // ok
I said all types are expressions.
(Even though the language does not admit it yet.)
Not all expressions are types.
|
Copyright © 1999-2021 by the D Language Foundation