www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - proposed syntax for tuple: t{} and TypeTuple: T{} (cf precedent of

reply Timothee Cour via Digitalmars-d <digitalmars-d puremagic.com> writes:
{} 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{...}
Apr 04 2016
next sibling parent reply ag0aep6g <anonymous example.com> writes:
On 05.04.2016 07:45, Timothee Cour via Digitalmars-d wrote:
 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)
 ----
In existing syntax, most {...} blocks can contain semicolon separated declarations. Your proposed constructs would be comma separated lists. I'd vote for other delimiters because of that. Static struct initializers are the exception in existing syntax, but they stick out, and they're not used often. Parentheses are not an option because of arbitrary identifiers in function calls and such, and making `t`/`T` keywords for this purpose doesn't seem wise. That leaves square brackets. `t[...]` doesn't clash with anything, as far as I see. And it makes a good fit for the feature, in my opinion. So I'd prefer `t[...]` over `t{...}`. I'm not sure if the new syntax is worth adding, though. `T{...}` (or `T[...]`) saves just one character over `T!(...)`. The latter can be done without touching the language. For the value tuple, one can do `alias t = std.typecons.tuple;` which gives you `t(...)`. That's just as short as `t{...}`. But maybe std.typecons.tuple is lacking somehow. A more proper `t(...)` could be implemented when functions could return tuples, which would also be desirable if we had `t{...}` syntax. So implementing `T!(...)` and `t(...)` in D seems like the way to go to me. And maybe allow functions to return tuples.
Apr 05 2016
parent Nick Treleaven <ntrel-pub mybtinternet.com> writes:
On Tuesday, 5 April 2016 at 14:00:46 UTC, ag0aep6g wrote:
 I'm not sure if the new syntax is worth adding, though. 
 `T{...}` (or `T[...]`) saves just one character over `T!(...)`. 
 The latter can be done without touching the language. For the 
 value tuple, one can do `alias t = std.typecons.tuple;` which 
 gives you `t(...)`. That's just as short as `t{...}`. But maybe 
 std.typecons.tuple is lacking somehow. A more proper `t(...)` 
 could be implemented when functions could return tuples, which 
 would also be desirable if we had `t{...}` syntax. So 
 implementing `T!(...)` and `t(...)` in D seems like the way to 
 go to me. And maybe allow functions to return tuples.
Functions can return std.typecons.tuple. All that is needed IMO is unpacking syntax: auto (int x, y) = someTuple; Rather than adding this specific feature, we could allow better, have Rust-like pattern matching macros: macro unpack(Declaration...); $unpack(int x, auto y) = someTuple;
Apr 08 2016
prev sibling next sibling parent reply ZombineDev <petar.p.kirov gmail.com> writes:
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 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 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});
Apr 05 2016
next sibling parent reply jmh530 <john.michael.hall gmail.com> writes:
On Tuesday, 5 April 2016 at 15:29:06 UTC, ZombineDev wrote:
 Action action = {}; // error: `{}` is an empty tuple, can't be 
 assigned to delegates
 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.
Is making this Action action = {}; an error a breaking change? It currently compiles without error and I can get the typeof(action) as void delegate(), though I can't really do much of anything with it. Similarly for empty function literals.
Apr 05 2016
parent ZombineDev <petar.p.kirov gmail.com> writes:
On Tuesday, 5 April 2016 at 16:34:49 UTC, jmh530 wrote:
 On Tuesday, 5 April 2016 at 15:29:06 UTC, ZombineDev wrote:
 Action action = {}; // error: `{}` is an empty tuple, can't be 
 assigned to delegates
 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.
Is making this Action action = {}; an error a breaking change? It currently compiles without error and I can get the typeof(action) as void delegate(), though I can't really do much of anything with it. Similarly for empty function literals.
Yes, I think it would be a breaking change, if my proposal is accepted.
Apr 05 2016
prev sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
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}) // <- ? 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.) 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.)
 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;
Apr 05 2016
parent reply ZombineDev <petar.p.kirov gmail.com> writes:
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. 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; }
 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. 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 :(
Apr 05 2016
parent Timon Gehr <timon.gehr gmx.ch> writes:
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.
Apr 05 2016
prev sibling parent reply Jack Stouffer <jack jackstouffer.com> writes:
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{...}
Tuple and AliasSeq are library types, so the chance that they will be added into the language is slim to none.
Apr 05 2016
parent Adam D. Ruppe <destructionator gmail.com> writes:
On Tuesday, 5 April 2016 at 16:56:15 UTC, Jack Stouffer wrote:
 Tuple and AliasSeq are library types, so the chance that they 
 will be added into the language is slim to none.
Yes on Tuple, but AliasSeq actually is in the language (just unnamed there, it is what you get with T... in a template argument list) and isn't actually a type at all. It is just a list of compile time names.
Apr 05 2016