Discussion Thread: DIP 1037--Add Unary Operator ...--Community Review Round 1

Q. Schroll qs.il.paperinik at gmail.com
Mon Nov 2 22:54:16 UTC 2020

On Wednesday, 28 October 2020 at 10:57:37 UTC, Jacob Carlborg 
> 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 

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 

     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.

[3] https://run.dlang.io/is/GmgAaG
[4] https://run.dlang.io/is/DeGZF7

More information about the Digitalmars-d mailing list