proposed syntax for tuple: t{} and TypeTuple: T{} (cf precedent of q{...})

Timon Gehr via Digitalmars-d digitalmars-d at puremagic.com
Tue Apr 5 15:43:03 PDT 2016


On 05.04.2016 22:48, ZombineDev wrote:
> On Tuesday, 5 April 2016 at 20:13:59 UTC, Timon Gehr wrote:
>> On 05.04.2016 17:29, ZombineDev wrote:
>>> On Tuesday, 5 April 2016 at 05:45:08 UTC, Timothee Cour wrote:
>>>> {} for tuples hasn't worked out since it was deemed ambiguous with
>>>> delegate syntax (was it for the case of empty statements/tuple?).
>>>>
>>>> How about the following syntax instead:
>>>>
>>>> ----
>>>> {} // delegate (existing syntax)
>>>> q{...} // string literal (existing syntax)
>>>> t{...} // tuple(a,b) (proposed syntax)
>>>> T{...} // TypeTuple!(a,b) (proposed syntax)
>>>> ----
>>>>
>>>> See also [1] where i propose i{...} for a D analog of C++11's uniform
>>>> initialization.
>>>>
>>>>
>>>> [1] EMAIL: uniform initialization in D (as in C++11): i{...}
>>>
>>> I don't think that t or T is needed in front of {}.
>>>
>>> 1) Function literals / lambdas / delegates:
>>> If someone wants an empty function literal, they just have to use (){}
>>> instead of {}:
>>> alias Action = void delegate();
>>> Action action = (){}; // instead of
>>> Action action = {}; // error: `{}` is an empty tuple, can't be assigned
>>> to delegates
>>
>> (This specific case would actually be unproblematic. {} can be
>> polysemous.)
>>
>>> auto t = {}; // deduced as an empty tuple.
>>> Also, the non-empty {} syntax can't be mistaken for a function literal
>>> because non-empty function literals always have at least one statement
>>> that ends with a semicolon.
>>>
>>> 2) Tuples and AliasSeq-s.
>>> Correct me if I'm wrong, but I think that in all cases the expression is
>>> unambiguous:
>>> auto t1 = {3, 4}; // Tuple
>>> enum t2 = {3, 4}; // Tuple
>>> alias t3 = {3, 4}; // AliasSeq
>>> ...
>>
>> This is moot.
>>
>> template T(alias a,alias b){}
>> template T(alias a){}
>>
>>
>> T!({1,2}) // <- ?
>
> The answer to this question and all similar cases is that is that
> {1,2} is rewritten to AliasSeq!(1, 2). In this particular case it
> auto-expands and calls the T template with two alias parameters.
>
>> Note that template alias parameters can accept values. (Other alias
>> declarations can too, possibly depending on how you look at it; the
>> language grammar is a little warty there.)
>
> Yes I know. And I see no problem with this.
> ...

There might have been some underlying misunderstanding here.
My guess is that you want the new built-in tuple syntax to be lowered to 
expression sequences? (I don't.)


> template K(alias fun, alias var, size_t idx, string str, T, Y...)
>
> int local = 42;
>
> K!(AliasSeq!(x => x * 2, local, 1 + 5, "asd", int, float, double));
> K!({ x => x * 2, local, 1 + 5, "asd", int, float, double });
> // also the same as:
> K!(x => x * 2, local, 1 + 5, { "asd", int, {float, double} });
>
>> I don't think there should be separate syntax for 'AliasSeq'
>> especially if it resembles tuple syntax. (The design is already
>> confusing enough, for no gain.)
>
> Well it would be a pretty big whole in the language if you could do
> tuple, but not alias sequences. Also it's nice to do:
>
> {float, float} scale({float, float} vec, float x)
> {
>      return vec * x;
> }
> ...

IMAO any design that tries to make wacky auto-expansion even more 
prominent is not good enough. Auto-expansion should be a derived notion 
at best. (I.e. there are tuples that are actually tuples, and then they 
might have an .expand property.)

(Also, note that multiple return values are explicitly ruled out at the 
moment.)


>>> void foo(Tuple!(int, int) x);
>>> foo({3, 4}); // same as foo(t1), or foo(t2)
>>>
>>> template staticMap(alias F, T...);
>>> alias constTypes = staticMap!(  constOf, { int, float, void[] } );
>>> static assert (is(  constTypes == { const(int), const(float),
>>> const(void[]) }  );
>>>
>>> writefln!({int, string, double})("%s %s %s", {3, "test", 4.2});
>>
>> That highlights another flaw in AliasSeq. This should do the trick,
>> but does not:
>> alias constTypes = const(AliasSeq!(int,float,void[]));
>> pragma(msg, constTypes); // (int, float, void[]) // wat?
>>
>>
>> This means that
>>
>> auto a=...;
>> const b=a;
>>
>> is not always the same as
>>
>> auto a=...;
>> const(typeof(a)) b=a;
>
> Yeah this looks like a bug in the current implementation.

Hopefully. Hard to tell. Walter?


> I also find
> the following limitation unfortunate:
>
> struct Point3 { int x, y, z; }
>
> Point3 a, b, c;
> c = a.tupleof + b.tupleof; // doesn't work :(
>


There are many, way more arbitrary, limitations. E.g. auto-expansion 
does not work in case labels, expression sequences cannot be operands of 
the comma operator and ternary operator and they cannot be returned from 
functions.


The main reason why AliasSeq is hard to evolve is that it is basically 
fubar'd. I don't know if you know about this:

alias Seq(T...)=T;
void main(){
     int x=0;
     Seq!(int,int) y = ++x;
     assert(y[0]==1 && y[1]==2);
}

Unless breaking changes are allowed, any design that builds on AliasSeq 
will be... funny.




More information about the Digitalmars-d mailing list