www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Tuple DIP

reply Timon Gehr <timon.gehr gmx.ch> writes:
As promised [1], I have started setting up a DIP to improve tuple 
ergonomics in D:

https://github.com/tgehr/DIPs/blob/tuple-syntax/DIPs/DIP1xxx-tg.md


This DIP aims to make code like the following valid D:

---
auto (a, b) = (1, 2);
(int a, int b) = (1, 2);
---

---
foreach((sum, diff); [(1, 2), (4, 3)].map!((a, b) => (a + b, a - b)))
{
     writeln(sum, " ", diff);
}
/+ prints:
3 -1
7 1
+/
---

Before going ahead with it, I'd like some preliminary community input:

- I'm not yet completely satisfied with the DIP.
   (See section "Limitations".)
   Please let me know suggestions or further concerns you might have.


- There are good example use cases missing. While I'm confident I could
   invent a few of them given a little time, I thought maybe I can
   expedite the process and make the point more convincingly by asking
   for use cases you encountered in your own code. The DIP already
   contains an example due to bearophile.


[1] https://forum.dlang.org/post/or625h$2hns$1 digitalmars.com
Jan 12
next sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 12.01.2018 23:44, Timon Gehr wrote:
 ...
 
 Before going ahead with it, I'd like some preliminary community input:
 ...
Also, if you have more links to forum posts requesting related features, that would be useful (googling turned up the ones that are in the DIP, but I know that there were more).
Jan 12
prev sibling next sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 12.01.2018 23:44, Timon Gehr wrote:
 
 ---
 auto (a, b) = (1, 2);
 (int a, int b) = (1, 2);
 ---
(The two lines are two independent examples :o).)
Jan 12
prev sibling next sibling parent reply Basile B. <b2.temp gmx.com> writes:
On Friday, 12 January 2018 at 22:44:48 UTC, Timon Gehr wrote:
 As promised [1], I have started setting up a DIP to improve 
 tuple ergonomics in D:

 https://github.com/tgehr/DIPs/blob/tuple-syntax/DIPs/DIP1xxx-tg.md
markdown trick: you can use ```diff ``` for a nicer grammar section.
Jan 12
parent Timon Gehr <timon.gehr gmx.ch> writes:
On 13.01.2018 00:16, Basile B. wrote:
 On Friday, 12 January 2018 at 22:44:48 UTC, Timon Gehr wrote:
 As promised [1], I have started setting up a DIP to improve tuple 
 ergonomics in D:

 https://github.com/tgehr/DIPs/blob/tuple-syntax/DIPs/DIP1xxx-tg.md
markdown trick: you can use ```diff ``` for a nicer grammar section.
Updated, thanks!
Jan 12
prev sibling next sibling parent reply Mark <smarksc gmail.com> writes:
On Friday, 12 January 2018 at 22:44:48 UTC, Timon Gehr wrote:
 As promised [1], I have started setting up a DIP to improve 
 tuple ergonomics in D:

 https://github.com/tgehr/DIPs/blob/tuple-syntax/DIPs/DIP1xxx-tg.md


 This DIP aims to make code like the following valid D:

 ---
 auto (a, b) = (1, 2);
 (int a, int b) = (1, 2);
 ---

 ---
 foreach((sum, diff); [(1, 2), (4, 3)].map!((a, b) => (a + b, a 
 - b)))
 {
     writeln(sum, " ", diff);
 }
 /+ prints:
 3 -1
 7 1
 +/
 ---

 Before going ahead with it, I'd like some preliminary community 
 input:

 - I'm not yet completely satisfied with the DIP.
   (See section "Limitations".)
   Please let me know suggestions or further concerns you might 
 have.


 - There are good example use cases missing. While I'm confident 
 I could
   invent a few of them given a little time, I thought maybe I 
 can
   expedite the process and make the point more convincingly by 
 asking
   for use cases you encountered in your own code. The DIP 
 already
   contains an example due to bearophile.


 [1] https://forum.dlang.org/post/or625h$2hns$1 digitalmars.com
Could we also support function tuples? For instance: int sum(int a, int b) { return a+b; } int diff(int a, int b) { return a-b; } (int, int) f = (sum, diff) // no ";" for consistency with existing syntax int (x,y) = f(1, 2); // x=3, y=-1 int (w,z) = (1, 2).f() // same as above, UFCS int (u,v) = (1, 2).(sum, diff) // same as above, "lambda tuple" In the last example, (sum, diff) is basically lowered to (x,y) => (sum(x,y), diff(x,y)).
Jan 12
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 13.01.2018 01:20, Mark wrote:
 
 Could we also support function tuples?
In principle, yes, though I imagine it is a lot harder to argue for its inclusion than for that of the features currently proposed in the DIP, because existing language features already come rather close.
 For instance:
 
 int sum(int a, int b) { return a+b; }
 int diff(int a, int b) { return a-b; }
 
 (int, int) f = (sum, diff) // no ";" for consistency with existing syntax
No ";" is inconsistent. Also the type of f cannot be (int, int), and (sum, diff) would try to call sum and diff with 0 arguments and fail.
 int (x,y) = f(1, 2); // x=3, y=-1
 int (w,z) = (1, 2).f() // same as above, UFCS
 int (u,v) = (1, 2).(sum, diff) // same as above, "lambda tuple"
 
 In the last example, (sum, diff) is basically lowered to (x,y) => 
 (sum(x,y), diff(x,y)).
I think this is easy enough to achieve without dedicated syntax: import std.typecons; template apply(F...){ auto apply(T)(T arg){ import std.conv, std.range, std.algorithm; return mixin(text("(",iota(F.length).map!(i=>text("F[",i,"](arg)")).join(","),")")); } } void main(){ int sum(int a, int b) { return a+b; } int diff(int a, int b) { return a-b; } auto (u,v)=(1,2).apply!(sum, diff); import std.stdio; writeln(u," ",v); }
Jan 12
parent Mark <smarksc gmail.com> writes:
On Saturday, 13 January 2018 at 00:51:51 UTC, Timon Gehr wrote:
 On 13.01.2018 01:20, Mark wrote:
 int (x,y) = f(1, 2); // x=3, y=-1
 int (w,z) = (1, 2).f() // same as above, UFCS
 int (u,v) = (1, 2).(sum, diff) // same as above, "lambda tuple"
 
 In the last example, (sum, diff) is basically lowered to (x,y) 
 => (sum(x,y), diff(x,y)).
I think this is easy enough to achieve without dedicated syntax: import std.typecons; template apply(F...){ auto apply(T)(T arg){ import std.conv, std.range, std.algorithm; return mixin(text("(",iota(F.length).map!(i=>text("F[",i,"](arg)")).join(","),")")); } } void main(){ int sum(int a, int b) { return a+b; } int diff(int a, int b) { return a-b; } auto (u,v)=(1,2).apply!(sum, diff); import std.stdio; writeln(u," ",v); }
I didn't think of that. That's cool! :)
Jan 13
prev sibling next sibling parent reply Chris M. <chrismohrfeld comcast.net> writes:
On Friday, 12 January 2018 at 22:44:48 UTC, Timon Gehr wrote:
 As promised [1], I have started setting up a DIP to improve 
 tuple ergonomics in D:

 [...]
Yes please
Jan 12
parent =?UTF-8?B?Tm9yZGzDtnc=?= <per.nordlow gmail.com> writes:
On Saturday, 13 January 2018 at 00:37:48 UTC, Chris M. wrote:
 On Friday, 12 January 2018 at 22:44:48 UTC, Timon Gehr wrote:
 As promised [1], I have started setting up a DIP to improve 
 tuple ergonomics in D:

 [...]
Yes please
Very much agree.
Jan 13
prev sibling next sibling parent Rubn <where is.this> writes:
Should include an example of returning a tuple from a function. I 
know one of the pains with variadic templates is that they can't 
be returned.

So maybe something that goes over the following use case:


auto returnTuple(Args...)(Args args)
{
     return args;
}


(int a, float b) = returnTuple(4, 1.0f);


Or just returning your regular tuple:


(int, float) returnSomeTuple()
{
     return (10, 1.0f); // or whatever
}
Jan 12
prev sibling next sibling parent rikki cattermole <rikki cattermole.co.nz> writes:
On 12/01/2018 10:44 PM, Timon Gehr wrote:
 As promised [1], I have started setting up a DIP to improve tuple 
 ergonomics in D:
 
 https://github.com/tgehr/DIPs/blob/tuple-syntax/DIPs/DIP1xxx-tg.md
 
 
 This DIP aims to make code like the following valid D:
 
 ---
 auto (a, b) = (1, 2);
 (int a, int b) = (1, 2);
 ---
 
 ---
 foreach((sum, diff); [(1, 2), (4, 3)].map!((a, b) => (a + b, a - b)))
 {
      writeln(sum, " ", diff);
 }
 /+ prints:
 3 -1
 7 1
 +/
 ---
 
 Before going ahead with it, I'd like some preliminary community input:
 
 - I'm not yet completely satisfied with the DIP.
    (See section "Limitations".)
    Please let me know suggestions or further concerns you might have.
 
 
 - There are good example use cases missing. While I'm confident I could
    invent a few of them given a little time, I thought maybe I can
    expedite the process and make the point more convincingly by asking
    for use cases you encountered in your own code. The DIP already
    contains an example due to bearophile.
 
 
 [1] https://forum.dlang.org/post/or625h$2hns$1 digitalmars.com
I really dislike the syntax, it looks hard to parse. #{int, string} Where T... all equal types #{1, "str"} Where T... all equal values Alternatively: #(1, "str") Since it is "arguments" to "construct" it. Doesn't that look easier to parse and use? It can be just a bit of syntax suger around (in object.di): struct Tuple(T...) { alias Types = T; T args; // opIndex/opIndexAssign }
Jan 12
prev sibling next sibling parent SrMordred <patric.dexheimer gmail.com> writes:
On Friday, 12 January 2018 at 22:44:48 UTC, Timon Gehr wrote:
 As promised [1], I have started setting up a DIP to improve
+1, please.
Jan 12
prev sibling next sibling parent reply jmh530 <john.michael.hall gmail.com> writes:
On Friday, 12 January 2018 at 22:44:48 UTC, Timon Gehr wrote:
 As promised [1], I have started setting up a DIP to improve 
 tuple ergonomics in D:
 [snip]
I'm glad you're working on this. Proposal 1 is a little terse in explaining what you mean by unpacking AliasSeqs. You might explain it in a little more detail. Also, Proposal 1 starts with this example auto (a, b) = tuple(1, "2"); (int a, string b) = tuple(1, "2"); but it also looks natural to be able to write (int, string) (a, b) = tuple(1, "2"); it looks from some of the other proposals that if they combine together then this would also work. Proposal 3 could use an example with named tuples. In proposal 6, how does auto (a, _) = t; expand for multiple? Would you be forced to do auto (a, _, _, _, _, _) = t; if the tuple has 6 entries?
Jan 12
next sibling parent reply Basile B. <b2.temp gmx.com> writes:
On Saturday, 13 January 2018 at 02:08:03 UTC, jmh530 wrote:
 On Friday, 12 January 2018 at 22:44:48 UTC, Timon Gehr wrote:
 As promised [1], I have started setting up a DIP to improve 
 tuple ergonomics in D:
 [snip]
I'm glad you're working on this. Proposal 1 is a little terse in explaining what you mean by unpacking AliasSeqs. You might explain it in a little more detail. Also, Proposal 1 starts with this example auto (a, b) = tuple(1, "2"); (int a, string b) = tuple(1, "2"); but it also looks natural to be able to write (int, string) (a, b) = tuple(1, "2");
Really ? After the type should be the declarator. In this example there's no declarator but if you add it then it becomes very strange: (int, string) ab (a, b) = tuple(1, "2");
Jan 12
next sibling parent reply Basile B. <b2.temp gmx.com> writes:
On Saturday, 13 January 2018 at 02:15:37 UTC, Basile B. wrote:
 On Saturday, 13 January 2018 at 02:08:03 UTC, jmh530 wrote:
 On Friday, 12 January 2018 at 22:44:48 UTC, Timon Gehr wrote:
 As promised [1], I have started setting up a DIP to improve 
 tuple ergonomics in D:
 [snip]
I'm glad you're working on this. Proposal 1 is a little terse in explaining what you mean by unpacking AliasSeqs. You might explain it in a little more detail. Also, Proposal 1 starts with this example auto (a, b) = tuple(1, "2"); (int a, string b) = tuple(1, "2"); but it also looks natural to be able to write (int, string) (a, b) = tuple(1, "2");
Really ? After the type should be the declarator. In this example there's no declarator but if you add it then it becomes very strange: (int, string) ab (a, b) = tuple(1, "2");
Forgot to say that on the other hand (int a, string b) ab = tuple(1, "2"); works better.
Jan 12
parent Basile B. <b2.temp gmx.com> writes:
On Saturday, 13 January 2018 at 02:18:20 UTC, Basile B. wrote:
 On Saturday, 13 January 2018 at 02:15:37 UTC, Basile B. wrote:
 On Saturday, 13 January 2018 at 02:08:03 UTC, jmh530 wrote:
 [...]
Really ? After the type should be the declarator. In this example there's no declarator but if you add it then it becomes very strange: (int, string) ab (a, b) = tuple(1, "2");
Forgot to say that on the other hand (int a, string b) ab = tuple(1, "2"); works better.
Better check twice than one. Actually i see now that there's no Declarator as used here, i.e for the whole tuple. Curious.
Jan 12
prev sibling parent jmh530 <john.michael.hall gmail.com> writes:
On Saturday, 13 January 2018 at 02:15:37 UTC, Basile B. wrote:
 On Saturday, 13 January 2018 at 02:08:03 UTC, jmh530 wrote:
 [snip]
 Also, Proposal 1 starts with this example
 auto (a, b) = tuple(1, "2");
 (int a, string b) = tuple(1, "2");
 but it also looks natural to be able to write
 (int, string) (a, b) = tuple(1, "2");
Really ? After the type should be the declarator. In this example there's no declarator but if you add it then it becomes very strange: (int, string) ab (a, b) = tuple(1, "2");
I left out a word there...I had meant that it would be natural to replace the auto version with that version. I would think it would work in combination with Proposal 3. If auto (a, b) = tuple(1, "2"); works, then surely __Tuple!(int, string) (a, b) = tuple(1, "2"); should work, which is equivalent to (int, string) (a, b) = tuple(1, "2");
Jan 12
prev sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 13.01.2018 03:08, jmh530 wrote:
 On Friday, 12 January 2018 at 22:44:48 UTC, Timon Gehr wrote:
 As promised [1], I have started setting up a DIP to improve tuple 
 ergonomics in D:
 [snip]
I'm glad you're working on this. Proposal 1 is a little terse in explaining what you mean by unpacking AliasSeqs. You might explain it in a little more detail. ...
Will do. std.typecons.Tuple is a slightly more fancy version of the following: struct Tuple(T...){ T expand; // AliasSeq alias expand this; // inherits indexing/slicing etc. // with the proposal, also inherits unpacking }
 Also, Proposal 1 starts with this example
 auto (a, b) = tuple(1, "2");
 (int a, string b) = tuple(1, "2");
 but it also looks natural to be able to write
 (int, string) (a, b) = tuple(1, "2");
 it looks from some of the other proposals that if they combine together 
 then this would also work.
 ...
Well, "auto" is not a placeholder type, but I'll think about it.
 Proposal 3 could use an example with named tuples.
 
 In proposal 6, how does
 auto (a, _) = t;
 expand for multiple? Would you be forced to do
 auto (a, _, _, _, _, _) = t;
 if the tuple has 6 entries?
Yes and no. I'd imagine one would use auto a = t[0];
Jan 13
prev sibling next sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2018-01-12 23:44, Timon Gehr wrote:
 As promised [1], I have started setting up a DIP to improve tuple 
 ergonomics in D:
Perhaps I don't have enough knowledge about the existing different types of tuples but Proposal 1 [1] says: "We add the following syntactic sugar to unpack AliasSeq's" But the example doesn't contain a single "AliasSeq", only "tuple". [1] https://github.com/tgehr/DIPs/blob/tuple-syntax/DIPs/DIP1xxx-tg.md#proposal-1-unpacking-declarations -- /Jacob Carlborg
Jan 13
parent Timon Gehr <timon.gehr gmx.ch> writes:
On 13.01.2018 12:43, Jacob Carlborg wrote:
 On 2018-01-12 23:44, Timon Gehr wrote:
 As promised [1], I have started setting up a DIP to improve tuple 
 ergonomics in D:
Perhaps I don't have enough knowledge about the existing different types of tuples but Proposal 1 [1] says: "We add the following syntactic sugar to unpack AliasSeq's" But the example doesn't contain a single "AliasSeq", only "tuple". [1] https://github.com/tgehr/DIPs/blob/tuple-syntax/DIPs/DIP1xxx-tg.md#proposal-1-un acking-declarations
Tuples are structs with alias this to a member AliasSeq, but I can add another example that uses the AliasSeq directly.
Jan 13
prev sibling next sibling parent Ilya Yaroshenko <ilyayaroshenko gmail.com> writes:
On Friday, 12 January 2018 at 22:44:48 UTC, Timon Gehr wrote:
 As promised [1], I have started setting up a DIP to improve 
 tuple ergonomics in D:

 https://github.com/tgehr/DIPs/blob/tuple-syntax/DIPs/DIP1xxx-tg.md
 [1] https://forum.dlang.org/post/or625h$2hns$1 digitalmars.com
Awesome!!! Thank you for the proposal! -- Ilya
Jan 13
prev sibling next sibling parent reply Mengu <mengukagan gmail.com> writes:
On Friday, 12 January 2018 at 22:44:48 UTC, Timon Gehr wrote:
 As promised [1], I have started setting up a DIP to improve 
 tuple ergonomics in D:

 [...]
how do we vote for / support this DIP?
Jan 13
parent reply Timothee Cour <thelastmammoth gmail.com> writes:
https://github.com/tgehr/DIPs/blob/tuple-syntax/DIPs/DIP1xxx-tg.md#proposal-4-unpacking-assignments
```
(a, b) = t;
// shouldn't it be:
auto (a, b) = t;
```
?




On Sat, Jan 13, 2018 at 9:52 AM, Mengu via Digitalmars-d
<digitalmars-d puremagic.com> wrote:
 On Friday, 12 January 2018 at 22:44:48 UTC, Timon Gehr wrote:
 As promised [1], I have started setting up a DIP to improve tuple
 ergonomics in D:

 [...]
how do we vote for / support this DIP?
Jan 13
parent Timon Gehr <timon.gehr gmx.ch> writes:
On 13.01.2018 19:07, Timothee Cour wrote:
 https://github.com/tgehr/DIPs/blob/tuple-syntax/DIPs/DIP1xxx-tg.md#proposal-4-unpacking-assignments
 ```
 (a, b) = t;
 // shouldn't it be:
 auto (a, b) = t;
 ```
 ?
 
No, but there was a mistake in the code that explains the confusion. It should be: (int, string) t = (1, "2"); int a; string b; (a, b) = t; // note: a and b exist already, now a==1, b=="2" I have fixed it now. Proposal 4 is about allowing tuple literals of lvalues as the left hand side of an assignment.
Jan 13
prev sibling next sibling parent reply Timothee Cour <thelastmammoth gmail.com> writes:
https://github.com/tgehr/DIPs/blob/tuple-syntax/DIPs/DIP1xxx-tg.md#proposal-6-placeholder-name-_

 Symbols with the name _ should not be inserted into the symbol table.
why not use `?` instead of `_` ? no breaking change and should be unambiguous with (expr ? expr : expr) syntax On Fri, Jan 12, 2018 at 2:44 PM, Timon Gehr via Digitalmars-d <digitalmars-d puremagic.com> wrote:
 As promised [1], I have started setting up a DIP to improve tuple ergonomics
 in D:

 https://github.com/tgehr/DIPs/blob/tuple-syntax/DIPs/DIP1xxx-tg.md


 This DIP aims to make code like the following valid D:

 ---
 auto (a, b) = (1, 2);
 (int a, int b) = (1, 2);
 ---

 ---
 foreach((sum, diff); [(1, 2), (4, 3)].map!((a, b) => (a + b, a - b)))
 {
     writeln(sum, " ", diff);
 }
 /+ prints:
 3 -1
 7 1
 +/
 ---

 Before going ahead with it, I'd like some preliminary community input:

 - I'm not yet completely satisfied with the DIP.
   (See section "Limitations".)
   Please let me know suggestions or further concerns you might have.


 - There are good example use cases missing. While I'm confident I could
   invent a few of them given a little time, I thought maybe I can
   expedite the process and make the point more convincingly by asking
   for use cases you encountered in your own code. The DIP already
   contains an example due to bearophile.


 [1] https://forum.dlang.org/post/or625h$2hns$1 digitalmars.com
Jan 13
parent Timon Gehr <timon.gehr gmx.ch> writes:
On 13.01.2018 19:11, Timothee Cour wrote:
 https://github.com/tgehr/DIPs/blob/tuple-syntax/DIPs/DIP1xxx-tg.md#proposal-6-placeholder-name-_
 
 Symbols with the name _ should not be inserted into the symbol table.
why not use `?` instead of `_` ? no breaking change and should be unambiguous with (expr ? expr : expr) syntax
It's unambiguous but nonstandard and a bit noisy. Also, it's slightly harder to support in the parser (although that shouldn't be a big concern). However, this proposal is independent of all the other ones, so in the end it is up to Walter and Andrei.
Jan 13
prev sibling next sibling parent reply aberba <karabutaworld gmail.com> writes:
On Friday, 12 January 2018 at 22:44:48 UTC, Timon Gehr wrote:
 As promised [1], I have started setting up a DIP to improve 
 tuple ergonomics in D:

 https://github.com/tgehr/DIPs/blob/tuple-syntax/DIPs/DIP1xxx-tg.md


 This DIP aims to make code like the following valid D:

 ---
 auto (a, b) = (1, 2);
 (int a, int b) = (1, 2);
 ---

 ---
 foreach((sum, diff); [(1, 2), (4, 3)].map!((a, b) => (a + b, a 
 - b)))
 {
     writeln(sum, " ", diff);
 }
 /+ prints:
 3 -1
 7 1
 +/
 ---

 Before going ahead with it, I'd like some preliminary community 
 input:

 - I'm not yet completely satisfied with the DIP.
   (See section "Limitations".)
   Please let me know suggestions or further concerns you might 
 have.


 - There are good example use cases missing. While I'm confident 
 I could
   invent a few of them given a little time, I thought maybe I 
 can
   expedite the process and make the point more convincingly by 
 asking
   for use cases you encountered in your own code. The DIP 
 already
   contains an example due to bearophile.


 [1] https://forum.dlang.org/post/or625h$2hns$1 digitalmars.com
When I raised this feature for D, suggestions on the use of () instead of {} got me concerned. All languages that I know to have this feature (known as destructuring) use curly braces. Thats what kotlin and JavaScript (that I know have support) use. Let's not be Rust that goes with different syntax without any technical advantage. curly braces are more common (So to speak). auto (name, email) = fetchUser(); vs auto {name, email} = fetchUser();
Jan 13
next sibling parent reply rjframe <dlang ryanjframe.com> writes:
On Sat, 13 Jan 2018 19:43:48 +0000, aberba wrote:

 
 When I raised this feature for D, suggestions on the use of () instead
 of {} got me concerned. All languages that I know to have this feature
 (known as destructuring) use curly braces. Thats what kotlin and
 JavaScript (that I know have support) use. Let's not be Rust that goes
 with different syntax without any technical advantage. curly braces are
 more common (So to speak).
 
 auto (name, email) = fetchUser();
     vs
 auto {name, email} = fetchUser();
Python and Pony use (). C++17 uses []. Perhaps D should use <>? [not a serious question] It was hard for me not to use angled brackets for templates when I started with D, but now it's second nature. I think you're right, familiarity with other languages is important, but it isn't everything. I'm not sure I like the idea of ever reading `foo((a, b), c);`, but like templates, I'd get used to it.
Jan 13
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 13.01.2018 21:39, rjframe wrote:
 Python and Pony use (). C++17 uses [].
Any idea why C++17 went with [] ?
 Perhaps D should use <>? [not a
 serious question]
 
 It was hard for me not to use angled brackets for templates when I started
 with D, but now it's second nature. I think you're right, familiarity with
 other languages is important, but it isn't everything.
 ...
I'd like to stress again that the proposed syntax is standard.
 I'm not sure I like the idea of ever reading `foo((a, b), c);`, but like
 templates, I'd get used to it.
It would actually be unsatisfying to have two distinct ways to group together a heterogeneous list (Tuples vs. function argument lists.) foo((a, b), c); auto args = ((a, b), c); foo(args);
Jan 13
next sibling parent reply rjframe <dlang ryanjframe.com> writes:
On Sat, 13 Jan 2018 21:57:31 +0100, Timon Gehr wrote:

 On 13.01.2018 21:39, rjframe wrote:
 Python and Pony use (). C++17 uses [].
Any idea why C++17 went with [] ?
I don't know; the paper[1] says it was due to "feedback from the EWG session in Jacksonville".
 
 It would actually be unsatisfying to have two distinct ways to group
 together a heterogeneous list (Tuples vs. function argument lists.)
 
 foo((a, b), c);
 
 auto args = ((a, b), c);
 foo(args);
It makes sense; I just know I'm going to end up overlooking them while scanning code until I get used to it. [1]: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0217r3.html
Jan 13
parent rjframe <dlang ryanjframe.com> writes:
On Sat, 13 Jan 2018 22:10:39 +0000, rjframe wrote:

 On Sat, 13 Jan 2018 21:57:31 +0100, Timon Gehr wrote:
 
 On 13.01.2018 21:39, rjframe wrote:
 Python and Pony use (). C++17 uses [].
Any idea why C++17 went with [] ?
I don't know; the paper[1] says it was due to "feedback from the EWG session in Jacksonville".
Not really tuples; but integrated with structs with tuple-like syntax.
Jan 13
prev sibling parent Mark <smarksc gmail.com> writes:
On Saturday, 13 January 2018 at 20:57:31 UTC, Timon Gehr wrote:
 On 13.01.2018 21:39, rjframe wrote:
 Python and Pony use (). C++17 uses [].
Any idea why C++17 went with [] ?
 Perhaps D should use <>? [not a
 serious question]
 
 It was hard for me not to use angled brackets for templates 
 when I started
 with D, but now it's second nature. I think you're right, 
 familiarity with
 other languages is important, but it isn't everything.
 ...
I'd like to stress again that the proposed syntax is standard.
 I'm not sure I like the idea of ever reading `foo((a, b), 
 c);`, but like
 templates, I'd get used to it.
It would actually be unsatisfying to have two distinct ways to group together a heterogeneous list (Tuples vs. function argument lists.) foo((a, b), c); auto args = ((a, b), c); foo(args);
Yeah. Consider the implications for UFCS: you'd want both (a, b).foo(c) and ((a, b), c).foo() to work.
Jan 13
prev sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 13.01.2018 20:43, aberba wrote:
 
 When I raised this feature for D, suggestions on the use of () instead 
 of {} got me concerned. All languages that I know to have this feature 
 (known as destructuring) use curly braces.
It seems that this is actually not the case. Anyway, I'd suggest having a look at more languages.
 Thats what kotlin and JavaScript (that I know have support) use.
They actually do not. https://kotlinlang.org/docs/reference/multi-declarations.html I.e. Kotlin also uses parentheses. They do this because it is standard. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment In JavaScript, curly braces are used for object destructuring, not tuple destructuring. JavaScript does not have tuples, because without typing, they would be redundant with arrays. For array destructuring, JavaScript uses square brackets. This makes a lot of sense, as square brackets are also used to write array literals. Tuples are usually written using parentheses.
 Let's not be Rust that goes 
 with different syntax without any technical advantage.
The syntax the DIP proposes is as close to standard as it gets. (Also, the idea that Rust syntax has no technical advantage whatsoever over C syntax is ridiculous. Can't say I enjoy all of their choices though, e.g. using + for multiple trait bounds is atrocious.)
 curly braces are more common (So to speak).
 
They really are not.
 auto (name, email) = fetchUser();
     vs
 auto {name, email} = fetchUser();
 
Jan 13
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 13.01.2018 21:49, Timon Gehr wrote:
 
 auto (name, email) = fetchUser();
     vs
 auto {name, email} = fetchUser();
BTW: What do you think each of those do? I'd expect the following: --- auto (name, email) = fetchUser(); => auto __tmp = fetchUser(); auto name = __tmp[0], email = __tmp[1]; --- --- auto {name, email} = fetchUser(); => auto __tmp = fetchUser(); auto name = __tmp.name, email = __tmp.email; --- The DIP proposes only the first one of those features, and only for AliasSeq's or types that alias this to an AliasSeq (such as tuples).
Jan 13
parent MrSmith <mrsmith33 yandex.ru> writes:
On Saturday, 13 January 2018 at 21:05:27 UTC, Timon Gehr wrote:
 On 13.01.2018 21:49, Timon Gehr wrote:
 
 auto (name, email) = fetchUser();
     vs
 auto {name, email} = fetchUser();
BTW: What do you think each of those do? I'd expect the following: --- auto (name, email) = fetchUser(); => auto __tmp = fetchUser(); auto name = __tmp[0], email = __tmp[1]; --- --- auto {name, email} = fetchUser(); => auto __tmp = fetchUser(); auto name = __tmp.name, email = __tmp.email; --- The DIP proposes only the first one of those features, and only for AliasSeq's or types that alias this to an AliasSeq (such as tuples).
How about this syntax for getting a tuple of fields: --- auto (name, email) = fetchUser().(name, email); ---
Jan 13
prev sibling next sibling parent Timothee Cour <thelastmammoth gmail.com> writes:
it would also solve a long-standing issue of passing runtime optional
arguments along with variadic templates, eg:

current:
```
# current: bad, causes template bloat (1 template per call site)
void log(string file=__FILE__, int line=__LINE__, T...)(T a);
# usage:
log(1, "foo");

# with this DIP
void log(T...)(T a, string file=__FILE__, int line=__LINE__);
log((1, "foo"));
```

still not ideal as syntax is not as nice, but at least it removes template bloat


On Fri, Jan 12, 2018 at 2:44 PM, Timon Gehr via Digitalmars-d
<digitalmars-d puremagic.com> wrote:
 As promised [1], I have started setting up a DIP to improve tuple ergonomics
 in D:

 https://github.com/tgehr/DIPs/blob/tuple-syntax/DIPs/DIP1xxx-tg.md


 This DIP aims to make code like the following valid D:

 ---
 auto (a, b) = (1, 2);
 (int a, int b) = (1, 2);
 ---

 ---
 foreach((sum, diff); [(1, 2), (4, 3)].map!((a, b) => (a + b, a - b)))
 {
     writeln(sum, " ", diff);
 }
 /+ prints:
 3 -1
 7 1
 +/
 ---

 Before going ahead with it, I'd like some preliminary community input:

 - I'm not yet completely satisfied with the DIP.
   (See section "Limitations".)
   Please let me know suggestions or further concerns you might have.


 - There are good example use cases missing. While I'm confident I could
   invent a few of them given a little time, I thought maybe I can
   expedite the process and make the point more convincingly by asking
   for use cases you encountered in your own code. The DIP already
   contains an example due to bearophile.


 [1] https://forum.dlang.org/post/or625h$2hns$1 digitalmars.com
Jan 13
prev sibling next sibling parent reply Timothee Cour <thelastmammoth gmail.com> writes:
the DIP says this replace std.typecons.TypeTuple however no mention is
made of named arguments, so I don't see how they could be a
replacement (nor how would that allow for a migration path) without
mentioning a word on this, eg:

what would be the equivalent of this ?
` writeln(tuple!("x", "y", "z")(2, 3, 4).y); `

On Fri, Jan 12, 2018 at 2:44 PM, Timon Gehr via Digitalmars-d
<digitalmars-d puremagic.com> wrote:
 As promised [1], I have started setting up a DIP to improve tuple ergonomics
 in D:

 https://github.com/tgehr/DIPs/blob/tuple-syntax/DIPs/DIP1xxx-tg.md


 This DIP aims to make code like the following valid D:

 ---
 auto (a, b) = (1, 2);
 (int a, int b) = (1, 2);
 ---

 ---
 foreach((sum, diff); [(1, 2), (4, 3)].map!((a, b) => (a + b, a - b)))
 {
     writeln(sum, " ", diff);
 }
 /+ prints:
 3 -1
 7 1
 +/
 ---

 Before going ahead with it, I'd like some preliminary community input:

 - I'm not yet completely satisfied with the DIP.
   (See section "Limitations".)
   Please let me know suggestions or further concerns you might have.


 - There are good example use cases missing. While I'm confident I could
   invent a few of them given a little time, I thought maybe I can
   expedite the process and make the point more convincingly by asking
   for use cases you encountered in your own code. The DIP already
   contains an example due to bearophile.


 [1] https://forum.dlang.org/post/or625h$2hns$1 digitalmars.com
Jan 13
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 13.01.2018 23:57, Timothee Cour wrote:
 the DIP says this replace std.typecons.TypeTuple however no mention is
 made of named arguments, so I don't see how they could be a
 replacement (nor how would that allow for a migration path) without
 mentioning a word on this, eg:
 
 what would be the equivalent of this ?
 ` writeln(tuple!("x", "y", "z")(2, 3, 4).y); `
It would continue to work the same way. I did consider adding a proposal for built-in named tuple syntax: writeln((x: 2, y: 3, z: 4).y); (int a, double b) t = (a: 1, b: 2.0); int x = t.a; double y = t.b; But I decided against it to keep the DIP focused, and because of potential future-proofing hazards related to named arguments. (For Phobos tuples, name mismatches are simply ignored when converting one named tuple into another, which I'm not sure is the best possible behavior, but the goal of this DIP is not to fight this design.)
Jan 13
parent reply Martin Nowak <code+news.digitalmars dawg.eu> writes:
On 01/14/2018 12:21 AM, Timon Gehr wrote:
 what would be the equivalent of this ?
 ` writeln(tuple!("x", "y", "z")(2, 3, 4).y); `
It would continue to work the same way. I did consider adding a proposal for built-in named tuple syntax: writeln((x: 2, y: 3, z: 4).y); (int a, double b) t = (a: 1, b: 2.0); int x = t.a; double y = t.b;
Tuples are anonymous bundles, when you want a product type with field names use a struct.
Feb 16
next sibling parent reply Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Friday, February 16, 2018 21:01:02 Martin Nowak via Digitalmars-d wrote:
 On 01/14/2018 12:21 AM, Timon Gehr wrote:
 what would be the equivalent of this ?
 ` writeln(tuple!("x", "y", "z")(2, 3, 4).y); `
It would continue to work the same way. I did consider adding a proposal for built-in named tuple syntax: writeln((x: 2, y: 3, z: 4).y); (int a, double b) t = (a: 1, b: 2.0); int x = t.a; double y = t.b;
Tuples are anonymous bundles, when you want a product type with field names use a struct.
That's not necessarily unreasonable, but std.typecons.Tuple is frequently used as a convenient way to return a group of values, and the trend has been towards using named values, because those are easier to deal with as return values, because they're somewhat self-documenting at that point, and they're less error-prone. So, if we're talking about adding more complete tuples to the language, if they don't have support for names, you then have the problem of whether it's better to use the built-in tuples or something like std.typecons.Tuple with named values, and there's a pretty strong argument at that point that it's better to use the named tuples and lose whatever benefits the built-in tuples might provide, because the named tuples result in more maintainable code. - Jonathan M Davis
Feb 16
parent Timon Gehr <timon.gehr gmx.ch> writes:
On 16.02.2018 21:16, Jonathan M Davis wrote:
 On Friday, February 16, 2018 21:01:02 Martin Nowak via Digitalmars-d wrote:
 On 01/14/2018 12:21 AM, Timon Gehr wrote:
 what would be the equivalent of this ?
 ` writeln(tuple!("x", "y", "z")(2, 3, 4).y); `
It would continue to work the same way. I did consider adding a proposal for built-in named tuple syntax: writeln((x: 2, y: 3, z: 4).y); (int a, double b) t = (a: 1, b: 2.0); int x = t.a; double y = t.b;
Tuples are anonymous bundles, when you want a product type with field names use a struct.
That's not necessarily unreasonable, but std.typecons.Tuple is frequently used as a convenient way to return a group of values, and the trend has been towards using named values, because those are easier to deal with as return values, because they're somewhat self-documenting at that point, and they're less error-prone. So, if we're talking about adding more complete tuples to the language, if they don't have support for names, you then have the problem of whether it's better to use the built-in tuples or something like std.typecons.Tuple with named values, and there's a pretty strong argument at that point that it's better to use the named tuples and lose whatever benefits the built-in tuples might provide, because the named tuples result in more maintainable code. - Jonathan M Davis
This is not really problematic. Note that the /only/ improvement in the DIP that does not apply to library tuples is the tuple construction syntax.
Feb 16
prev sibling next sibling parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Fri, Feb 16, 2018 at 01:16:13PM -0700, Jonathan M Davis via Digitalmars-d
wrote:
 On Friday, February 16, 2018 21:01:02 Martin Nowak via Digitalmars-d wrote:
 On 01/14/2018 12:21 AM, Timon Gehr wrote:
 what would be the equivalent of this ?
 ` writeln(tuple!("x", "y", "z")(2, 3, 4).y); `
It would continue to work the same way. I did consider adding a proposal for built-in named tuple syntax: writeln((x: 2, y: 3, z: 4).y); (int a, double b) t = (a: 1, b: 2.0); int x = t.a; double y = t.b;
Tuples are anonymous bundles, when you want a product type with field names use a struct.
That's not necessarily unreasonable, but std.typecons.Tuple is frequently used as a convenient way to return a group of values, and the trend has been towards using named values, because those are easier to deal with as return values, because they're somewhat self-documenting at that point, and they're less error-prone. So, if we're talking about adding more complete tuples to the language, if they don't have support for names, you then have the problem of whether it's better to use the built-in tuples or something like std.typecons.Tuple with named values, and there's a pretty strong argument at that point that it's better to use the named tuples and lose whatever benefits the built-in tuples might provide, because the named tuples result in more maintainable code.
[...] Tuples with named fields are essentially anonymous structs. If we had those, 60% of what this DIP addresses would already have been solved. Cf.: https://forum.dlang.org/post/kfbnuc$1cro$1 digitalmars.com T -- Ignorance is bliss... until you suffer the consequences!
Feb 16
parent Timon Gehr <timon.gehr gmx.ch> writes:
On 16.02.2018 21:48, H. S. Teoh wrote:
 On Fri, Feb 16, 2018 at 01:16:13PM -0700, Jonathan M Davis via Digitalmars-d
wrote:
 On Friday, February 16, 2018 21:01:02 Martin Nowak via Digitalmars-d wrote:
 On 01/14/2018 12:21 AM, Timon Gehr wrote:
 what would be the equivalent of this ?
 ` writeln(tuple!("x", "y", "z")(2, 3, 4).y); `
It would continue to work the same way. I did consider adding a proposal for built-in named tuple syntax: writeln((x: 2, y: 3, z: 4).y); (int a, double b) t = (a: 1, b: 2.0); int x = t.a; double y = t.b;
Tuples are anonymous bundles, when you want a product type with field names use a struct.
That's not necessarily unreasonable, but std.typecons.Tuple is frequently used as a convenient way to return a group of values, and the trend has been towards using named values, because those are easier to deal with as return values, because they're somewhat self-documenting at that point, and they're less error-prone. So, if we're talking about adding more complete tuples to the language, if they don't have support for names, you then have the problem of whether it's better to use the built-in tuples or something like std.typecons.Tuple with named values, and there's a pretty strong argument at that point that it's better to use the named tuples and lose whatever benefits the built-in tuples might provide, because the named tuples result in more maintainable code.
[...] Tuples with named fields are essentially anonymous structs. If we had those, 60% of what this DIP addresses would already have been solved. Cf.: https://forum.dlang.org/post/kfbnuc$1cro$1 digitalmars.com T
You got that number a bit too high. The DIP is mostly about tuple unpacking.
Feb 16
prev sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 16.02.2018 21:01, Martin Nowak wrote:
 On 01/14/2018 12:21 AM, Timon Gehr wrote:
 what would be the equivalent of this ?
 ` writeln(tuple!("x", "y", "z")(2, 3, 4).y); `
It would continue to work the same way. I did consider adding a proposal for built-in named tuple syntax: writeln((x: 2, y: 3, z: 4).y); (int a, double b) t = (a: 1, b: 2.0); int x = t.a; double y = t.b;
Tuples are anonymous bundles, when you want a product type with field names use a struct.
I agree, but Phobos does not.
Feb 16
prev sibling next sibling parent reply Timothee Cour <thelastmammoth gmail.com> writes:
some people have suggested using `{a, b}` instead of `(a,b)` ; this
would not work because of ambiguity, eg:
`auto fun(){ return {}; }`
already has a meaning, so the empty tuple would not work.
so `()` is indeed better.

On Fri, Jan 12, 2018 at 2:44 PM, Timon Gehr via Digitalmars-d
<digitalmars-d puremagic.com> wrote:
 As promised [1], I have started setting up a DIP to improve tuple ergonomics
 in D:

 https://github.com/tgehr/DIPs/blob/tuple-syntax/DIPs/DIP1xxx-tg.md


 This DIP aims to make code like the following valid D:

 ---
 auto (a, b) = (1, 2);
 (int a, int b) = (1, 2);
 ---

 ---
 foreach((sum, diff); [(1, 2), (4, 3)].map!((a, b) => (a + b, a - b)))
 {
     writeln(sum, " ", diff);
 }
 /+ prints:
 3 -1
 7 1
 +/
 ---

 Before going ahead with it, I'd like some preliminary community input:

 - I'm not yet completely satisfied with the DIP.
   (See section "Limitations".)
   Please let me know suggestions or further concerns you might have.


 - There are good example use cases missing. While I'm confident I could
   invent a few of them given a little time, I thought maybe I can
   expedite the process and make the point more convincingly by asking
   for use cases you encountered in your own code. The DIP already
   contains an example due to bearophile.


 [1] https://forum.dlang.org/post/or625h$2hns$1 digitalmars.com
Jan 13
parent reply rikki cattermole <rikki cattermole.co.nz> writes:
On 13/01/2018 11:45 PM, Timothee Cour wrote:
 some people have suggested using `{a, b}` instead of `(a,b)` ; this
 would not work because of ambiguity, eg:
 `auto fun(){ return {}; }`
 already has a meaning, so the empty tuple would not work.
 so `()` is indeed better.
Easy fix, tuples must have a length greater than 0. A tuple with length 0 is by definition void.
Jan 13
parent Q. Schroll <qs.il.paperinik gmail.com> writes:
On Sunday, 14 January 2018 at 00:01:15 UTC, rikki cattermole 
wrote:
 On 13/01/2018 11:45 PM, Timothee Cour wrote:
 some people have suggested using `{a, b}` instead of `(a,b)` ; 
 this
 would not work because of ambiguity, eg:
 `auto fun(){ return {}; }`
 already has a meaning, so the empty tuple would not work.
 so `()` is indeed better.
Easy fix, tuples must have a length greater than 0. A tuple with length 0 is by definition void.
Zero tuples exist and don't have type void as their type has an object: the empty tuple. It's similar to the empty word, the empty array, etc. They naturally arise in corner cases of templates. You have to support them like static arrays of length 0. Effectively forbidding them would be an unreasonable limitation.
Jan 14
prev sibling next sibling parent reply Q. Schroll <qs.il.paperinik gmail.com> writes:
On Friday, 12 January 2018 at 22:44:48 UTC, Timon Gehr wrote:
 [...]
 This DIP aims to make code like the following valid D:

 ---
 auto (a, b) = (1, 2);
 (int a, int b) = (1, 2);
 ---
 [...]
How is (1, 2) different from [1, 2] (static array)? It makes no sense to me to have both and probably a bunch of conversion rules/functions. Why don't you consider extending (type-homogeneous) static arrays to (finite type enumerated) tuples? It solves - 1-tuples - comma operator vs. tuple literal instantly. You'd have T[n] as an alias for the tuple type consisting of n objects of type T. I've written something about that here: https://forum.dlang.org/post/wwgwwepihklttnqghcaq forum.dlang.org (sorry for my bad English in that post) The main reason I'd vote against the DIP: Parenthesis should only be used for operator precedence and function calls.
Jan 14
next sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 14.01.2018 15:55, Q. Schroll wrote:
 On Friday, 12 January 2018 at 22:44:48 UTC, Timon Gehr wrote:
 [...]
 This DIP aims to make code like the following valid D:

 ---
 auto (a, b) = (1, 2);
 (int a, int b) = (1, 2);
 ---
 [...]
How is (1, 2) different from [1, 2] (static array)?
The first is a tuple, the second is a static array. This distinction exists already, it is not proposed in this DIP. I.e., you could just as well ask "How is tuple(1, 2) different from [1, 2] (static array)?". A (probably non-exhaustive) answer is that dynamic arrays have a 'ptr' property; slicing a static array will produce a dynamic array; tuples alias this to an 'expand' property that gives the components as an AliasSeq; an empty tuple will take up 1 byte of space in a struct/class, but an empty static array will not; empty static arrays have an element type, 'void' is allowed as the element type of an empty static array; array literals are _dynamic_ arrays by default, enforcing homogeneous element types, while tuple literals give you heterogeneous _tuples_, ... None of this has much to do with the DIP though.
 It makes no sense to 
 me to have both and probably a bunch of conversion rules/functions.
 ...
The DIP proposes no new conversion rules, nor does it _introduce_ tuples. You'll need to complain about the status quo elsewhere; blaming the DIP for it makes no sense.
 Why don't you consider extending (type-homogeneous) static arrays to 
 (finite type enumerated) tuples?
Because tuples and arrays have significant differences as outlined above and tuple literal syntax is essentially useless if it needs to be accompanied by explicit type casts or annotations on every use. It's better to not add tuple syntax at all than to overload square brackets in this ad-hoc manner. Calling 'tuple(1, 2.0)' is less of a hassle than writing cast([int, double])[1, 2.0]. This is just not good language design.
 It solves
   - 1-tuples
There is already a solution.
   - comma operator vs. tuple literal
The comma operator is gone.
 instantly.
I think it introduces more problems than it solves.
 You'd have T[n] as an alias for the tuple type consisting of n objects 
 of type T.
 ...
So whether or not a tuple is instead a static array (according to the differences above) depends on whether or not the types happen to be homogeneous? I do understand very well the superficial aesthetic appeal, but this is unfortunately just not a workable approach.
 I've written something about that here:
 https://forum.dlang.org/post/wwgwwepihklttnqghcaq forum.dlang.org
(The DIP links to that thread.)
 (sorry for my bad English in that post)
 ...
The English is fine.
 The main reason I'd vote against the DIP: Parenthesis should only be 
 used for operator precedence and function calls.
You do realize that this translates to "just because"? (That, and you forgot about template instantiation, type constructor/typeof application, if/for/while/switch/scope/... statements, type casts, basic type constructor/new calls, ... (list wildly non-exhaustive).)
Jan 14
parent reply Timothee Cour <thelastmammoth gmail.com> writes:
actually I just learned that indeed sizeof(typeof(tuple()))=1, but why
is that? (at least for std.typecons.tuple)
maybe worth mentioning that in the DIP (with rationale)

On Sun, Jan 14, 2018 at 8:18 AM, Timon Gehr via Digitalmars-d
<digitalmars-d puremagic.com> wrote:
 On 14.01.2018 15:55, Q. Schroll wrote:
 On Friday, 12 January 2018 at 22:44:48 UTC, Timon Gehr wrote:
 [...]
 This DIP aims to make code like the following valid D:

 ---
 auto (a, b) = (1, 2);
 (int a, int b) = (1, 2);
 ---
 [...]
How is (1, 2) different from [1, 2] (static array)?
The first is a tuple, the second is a static array. This distinction exists already, it is not proposed in this DIP. I.e., you could just as well ask "How is tuple(1, 2) different from [1, 2] (static array)?". A (probably non-exhaustive) answer is that dynamic arrays have a 'ptr' property; slicing a static array will produce a dynamic array; tuples alias this to an 'expand' property that gives the components as an AliasSeq; an empty tuple will take up 1 byte of space in a struct/class, but an empty static array will not; empty static arrays have an element type, 'void' is allowed as the element type of an empty static array; array literals are _dynamic_ arrays by default, enforcing homogeneous element types, while tuple literals give you heterogeneous _tuples_, ... None of this has much to do with the DIP though.
 It makes no sense to me to have both and probably a bunch of conversion
 rules/functions.
 ...
The DIP proposes no new conversion rules, nor does it _introduce_ tuples. You'll need to complain about the status quo elsewhere; blaming the DIP for it makes no sense.
 Why don't you consider extending (type-homogeneous) static arrays to
 (finite type enumerated) tuples?
Because tuples and arrays have significant differences as outlined above and tuple literal syntax is essentially useless if it needs to be accompanied by explicit type casts or annotations on every use. It's better to not add tuple syntax at all than to overload square brackets in this ad-hoc manner. Calling 'tuple(1, 2.0)' is less of a hassle than writing cast([int, double])[1, 2.0]. This is just not good language design.
 It solves
   - 1-tuples
There is already a solution.
   - comma operator vs. tuple literal
The comma operator is gone.
 instantly.
I think it introduces more problems than it solves.
 You'd have T[n] as an alias for the tuple type consisting of n objects of
 type T.
 ...
So whether or not a tuple is instead a static array (according to the differences above) depends on whether or not the types happen to be homogeneous? I do understand very well the superficial aesthetic appeal, but this is unfortunately just not a workable approach.
 I've written something about that here:
 https://forum.dlang.org/post/wwgwwepihklttnqghcaq forum.dlang.org
(The DIP links to that thread.)
 (sorry for my bad English in that post)
 ...
The English is fine.
 The main reason I'd vote against the DIP: Parenthesis should only be used
 for operator precedence and function calls.
You do realize that this translates to "just because"? (That, and you forgot about template instantiation, type constructor/typeof application, if/for/while/switch/scope/... statements, type casts, basic type constructor/new calls, ... (list wildly non-exhaustive).)
Jan 14
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 14.01.2018 19:14, Timothee Cour wrote:
 actually I just learned that indeed sizeof(typeof(tuple()))=1, but why
 is that? (at least for std.typecons.tuple)
 maybe worth mentioning that in the DIP (with rationale)
It's inherited from C, where all struct instances have size at least 1. (Such that each of them has a distinct address.)
Jan 14
next sibling parent reply Timothee Cour <thelastmammoth gmail.com> writes:
On Sun, Jan 14, 2018 at 10:17 AM, Timon Gehr via Digitalmars-d
<digitalmars-d puremagic.com> wrote:
 On 14.01.2018 19:14, Timothee Cour wrote:
 actually I just learned that indeed sizeof(typeof(tuple()))=1, but why
 is that? (at least for std.typecons.tuple)
 maybe worth mentioning that in the DIP (with rationale)
It's inherited from C, where all struct instances have size at least 1. (Such that each of them has a distinct address.)
Should definitely be mentioned in the DIP to open that up for discussion; it breaks assumptions like sizeof(Tuple)=sum_i : tuple (sizeof(Ti)); even if that were the case in std.typecons.tuple, having it as builtin could behave differently.
Jan 14
parent Martin Nowak <code+news.digitalmars dawg.eu> writes:
On 01/14/2018 07:41 PM, Timothee Cour wrote:
 Should definitely be mentioned in the DIP to open that up for discussion;
 it breaks assumptions like sizeof(Tuple)=sum_i : tuple (sizeof(Ti));
That doesn't hold for all cases anyhow, as it seems were talking about closed tuples that are contiguous in memory and follow struct layout and alignment rules.
Feb 16
prev sibling next sibling parent Walter Bright <newshound2 digitalmars.com> writes:
On 1/14/2018 10:17 AM, Timon Gehr wrote:
 It's inherited from C, where all struct instances have size at least 1. (Such 
 that each of them has a distinct address.)
There are some peculiarities with that, like with multiple inheritance sometimes the size really is zero :-)
Jan 15
prev sibling parent reply Atila Neves <atila.neves gmail.com> writes:
On Sunday, 14 January 2018 at 18:17:38 UTC, Timon Gehr wrote:
 On 14.01.2018 19:14, Timothee Cour wrote:
 actually I just learned that indeed sizeof(typeof(tuple()))=1, 
 but why
 is that? (at least for std.typecons.tuple)
 maybe worth mentioning that in the DIP (with rationale)
It's inherited from C, where all struct instances have size at least 1. (Such that each of them has a distinct address.)
Inherited from C++. In C empty structs have size 0. This caused me all sorts of problems when importing C headers from C++ in funky codebases. foo.c: #include <stdio.h> struct Foo {}; int main() { printf("%zu\n", sizeof(struct Foo)); return 0; } % clear && gcc foo.c && ./a.out 0 % clear && gcc -xc++ foo.c && ./a.out 1 Atila
Jan 23
parent reply Petar Kirov [ZombineDev] <petar.p.kirov gmail.com> writes:
On Tuesday, 23 January 2018 at 11:04:33 UTC, Atila Neves wrote:
 On Sunday, 14 January 2018 at 18:17:38 UTC, Timon Gehr wrote:
 On 14.01.2018 19:14, Timothee Cour wrote:
 actually I just learned that indeed 
 sizeof(typeof(tuple()))=1, but why
 is that? (at least for std.typecons.tuple)
 maybe worth mentioning that in the DIP (with rationale)
It's inherited from C, where all struct instances have size at least 1. (Such that each of them has a distinct address.)
Inherited from C++. In C empty structs have size 0. This caused me all sorts of problems when importing C headers from C++ in funky codebases. foo.c: #include <stdio.h> struct Foo {}; int main() { printf("%zu\n", sizeof(struct Foo)); return 0; } % clear && gcc foo.c && ./a.out 0 % clear && gcc -xc++ foo.c && ./a.out 1 Atila
AFAIR the ISO C standard does not allow empty structs (as they would have no meaning). If you use the warnings as errors option, it won't compile: <source>:3:8: error: struct has no members [-Werror=pedantic] struct Foo {}; ^~~
Jan 23
parent Atila Neves <atila.neves gmail.com> writes:
On Tuesday, 23 January 2018 at 14:58:07 UTC, Petar Kirov 
[ZombineDev] wrote:
 On Tuesday, 23 January 2018 at 11:04:33 UTC, Atila Neves wrote:
 On Sunday, 14 January 2018 at 18:17:38 UTC, Timon Gehr wrote:
 On 14.01.2018 19:14, Timothee Cour wrote:
 actually I just learned that indeed 
 sizeof(typeof(tuple()))=1, but why
 is that? (at least for std.typecons.tuple)
 maybe worth mentioning that in the DIP (with rationale)
It's inherited from C, where all struct instances have size at least 1. (Such that each of them has a distinct address.)
Inherited from C++. In C empty structs have size 0. This caused me all sorts of problems when importing C headers from C++ in funky codebases. foo.c: #include <stdio.h> struct Foo {}; int main() { printf("%zu\n", sizeof(struct Foo)); return 0; } % clear && gcc foo.c && ./a.out 0 % clear && gcc -xc++ foo.c && ./a.out 1 Atila
AFAIR the ISO C standard does not allow empty structs (as they would have no meaning). If you use the warnings as errors option, it won't compile: <source>:3:8: error: struct has no members [-Werror=pedantic] struct Foo {}; ^~~
That's a warning treated as error. I checked and it seems that you're right about the C standard, although in practice compilers seem to accept empty structs. I knew that in C++ it's explicit that empty classes have size 1. Live and learn. Atila
Jan 23
prev sibling parent Walter Bright <newshound2 digitalmars.com> writes:
On 1/14/2018 6:55 AM, Q. Schroll wrote:
 How is (1, 2) different from [1, 2] (static array)?
It's a very good question. It's corollary is how is (1, 2) different from struct S { int a, b; } It does turn out that int[2] is structurally (!) the same as struct S. This is a property I've taken some pains to ensure stays valid, and it has turned out to be nicely useful. But consider: S foo(char a, char b); t = ('a', 'b'); foo(t); // equivalent to foo('a', 'b') That works. But: S s = {'a', 'b' }; foo(s); // Does not work It does not work is because s as a parameter has a distinctly different ABI than (char, char). The former consumes an int sized parameter, the latter two int sized parameters. A similar issue exists with the return value. So far, the issue of unification of tuples with arrays (and structs) has defeated me because of the fundamental structural differences in the ABI which we are stuck with.
Jan 15
prev sibling next sibling parent reply aliak <something something.com> writes:
On Friday, 12 January 2018 at 22:44:48 UTC, Timon Gehr wrote:
 As promised [1], I have started setting up a DIP to improve 
 tuple ergonomics in D:

 https://github.com/tgehr/DIPs/blob/tuple-syntax/DIPs/DIP1xxx-tg.md
 ...
Oh Yes! Question, would named tuples be able to be worked in or is that way out of scope? I.e. something for this use case: alias Color = Tuple!(int, "r", int, "g", int, "b"); Color f(Color input); auto color = f(Color(1, 2, 3)); writeln(color.r); Very handy with general graphics stuff, Point, Vector, etc Or for getting enumerate type functionality? range.enumerate() // Tuple!(int, "index", T, "value) So would we be able to work in something like: (r: int, g: int, b: int) f(int r, int g, int b) { return (100, 200, 150); } // Or more consistent with function syntax? (int r, int g, int b) f(int r, int g, int b) { return (100, 200, 150); } // And how about auto return named tuples? auto f(int r, int g, int b) { return (r: 100, g: 200, z: 150); }
Jan 16
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 16.01.2018 22:03, aliak wrote:
 On Friday, 12 January 2018 at 22:44:48 UTC, Timon Gehr wrote:
 As promised [1], I have started setting up a DIP to improve tuple 
 ergonomics in D:

 https://github.com/tgehr/DIPs/blob/tuple-syntax/DIPs/DIP1xxx-tg.md
 ...
Oh Yes! Question, would named tuples be able to be worked in or is that way out of scope? I.e. something for this use case: alias Color = Tuple!(int, "r", int, "g", int, "b"); Color f(Color input); auto color = f(Color(1, 2, 3)); writeln(color.r); Very handy with general graphics stuff, Point, Vector, etc Or for getting enumerate type functionality? range.enumerate() // Tuple!(int, "index", T, "value) So would we be able to work in something like: (r: int, g: int, b: int) f(int r, int g, int b) {     return (100, 200, 150); } // Or more consistent with function syntax? (int r, int g, int b) f(int r, int g, int b) {     return (100, 200, 150); } // And how about auto return named tuples? auto f(int r, int g, int b) {     return (r: 100, g: 200, z: 150); }
My thoughts were: http://forum.dlang.org/post/p3e4al$1jfc$1 digitalmars.com But as it has been requested more than once and it is a feature of existing Phobos tuples, I can add a proposal to the DIP that can be accepted/rejected independently, and add a few words to the "limitations" section.
Jan 16
next sibling parent reply jmh530 <john.michael.hall gmail.com> writes:
On Tuesday, 16 January 2018 at 21:21:04 UTC, Timon Gehr wrote:
 My thoughts were:
 http://forum.dlang.org/post/p3e4al$1jfc$1 digitalmars.com
A starting point could be an unnamed tuple built-in tuple type, but also not yet deprecating the built-in named tuple type in std.typecons.
 But as it has been requested more than once and it is a feature 
 of existing Phobos tuples, I can add a proposal to the DIP that 
 can be accepted/rejected independently, and add a few words to 
 the "limitations" section.
Sometimes when you give someone the option to agree or disagree to a bunch of different choices it's harder to come to agreement than if you keep things simple.
Jan 16
parent Timon Gehr <timon.gehr gmx.ch> writes:
On 16.01.2018 22:46, jmh530 wrote:
 On Tuesday, 16 January 2018 at 21:21:04 UTC, Timon Gehr wrote:
 My thoughts were:
 http://forum.dlang.org/post/p3e4al$1jfc$1 digitalmars.com
A starting point could be an unnamed tuple built-in tuple type, but also not yet deprecating the built-in named tuple type in std.typecons. ...
(That's what the current version of the DIP proposes. It does not aim to deprecate std.typecons.Tuple, it merely redirects it.)
 But as it has been requested more than once and it is a feature of 
 existing Phobos tuples, I can add a proposal to the DIP that can be 
 accepted/rejected independently, and add a few words to the 
 "limitations" section.
Sometimes when you give someone the option to agree or disagree to a bunch of different choices it's harder to come to agreement than if you keep things simple.
I'm perfectly fine with leaving it out for now.
Jan 16
prev sibling parent aliak <something something.com> writes:
On Tuesday, 16 January 2018 at 21:21:04 UTC, Timon Gehr wrote:
 My thoughts were:
 http://forum.dlang.org/post/p3e4al$1jfc$1 digitalmars.com

 But as it has been requested more than once and it is a feature 
 of existing Phobos tuples, I can add a proposal to the DIP that 
 can be accepted/rejected independently, and add a few words to 
 the "limitations" section.
Ah right, I guess I missed that! While it'd be pretty nice to have, it doesn't have to be now of course if you just want to get the main support through first, can be added in later at some point. As long as it's kept in mind while implementing unnamed tuples (which it seem you are doing anyway) then yay! Cheers!
Jan 17
prev sibling next sibling parent Guillaume Boucher <guillaume.boucher.d gmail.com> writes:
On Friday, 12 January 2018 at 22:44:48 UTC, Timon Gehr wrote:
 foreach((sum, diff); [(1, 2), (4, 3)].map!((a, b) => (a + b, a 
 - b)))
 {
     writeln(sum, " ", diff);
 }
I'm not a big fan of the foreach syntax. It's so easy to forget or accidentally add parentheses while coding, or read it wrongly while skimming over the code. Not sure if anything can be done against that, though. Maybe add an alternate "for (.. in ..)" syntax that doesn't have that problem?
Jan 16
prev sibling next sibling parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 1/12/18 5:44 PM, Timon Gehr wrote:
 As promised [1], I have started setting up a DIP to improve tuple 
 ergonomics in D:
 
 https://github.com/tgehr/DIPs/blob/tuple-syntax/DIPs/DIP1xxx-tg.md
Awesome! I can say I felt a lot more comfortable with the trailing-comma syntax after our last discussion :)
 Before going ahead with it, I'd like some preliminary community input:
 
 - I'm not yet completely satisfied with the DIP.
    (See section "Limitations".)
    Please let me know suggestions or further concerns you might have.
In the section discussing the breaking changes with proposal 3, you say: "The DIP author cannot see an obvious mitigation other than keeping std.typecons.Tuple and core.object.__Tuple separate instead of aliasing them." Well, what if std.typecons.Tuple can detect whether it's being used in a non-compatible way, and falls back on the original implementation? That is, when it works, it's an alias to object.__Tuple/__tuple, when it doesn't work, it's the old std.typecons.Tuple/tuple. I would expect it not to be that difficult to detect, but you don't specify exactly what the problems are so I'm not 100% sure I know what you are talking about :) An example would help. ----- About proposal 2, you say it's inspired by the conversation we had in the forums. I remember the discussion, but I'm not seeing the relationship with Proposal 2. I also am not sure about the example. It defines some function max, and then never uses it. I'm assuming somewhere there's a typo? In fact, I think the example would compile today as it doesn't use any tuples (I think), so I don't see the reason for it. -Steve
Jan 16
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 17.01.2018 02:20, Steven Schveighoffer wrote:
 On 1/12/18 5:44 PM, Timon Gehr wrote:
 As promised [1], I have started setting up a DIP to improve tuple 
 ergonomics in D:

 https://github.com/tgehr/DIPs/blob/tuple-syntax/DIPs/DIP1xxx-tg.md
Awesome! I can say I felt a lot more comfortable with the trailing-comma syntax after our last discussion :)
 Before going ahead with it, I'd like some preliminary community input:

 - I'm not yet completely satisfied with the DIP.
    (See section "Limitations".)
    Please let me know suggestions or further concerns you might have.
In the section discussing the breaking changes with proposal 3, you say: "The DIP author cannot see an obvious mitigation other than keeping std.typecons.Tuple and core.object.__Tuple separate instead of aliasing them." Well, what if std.typecons.Tuple can detect whether it's being used in a non-compatible way, and falls back on the original implementation? That is, when it works, it's an alias to object.__Tuple/__tuple, when it doesn't work, it's the old std.typecons.Tuple/tuple. I would expect it not to be that difficult to detect, but you don't specify exactly what the problems are so I'm not 100% sure I know what you are talking about :) An example would help. ...
The example is: auto t = tuple(1, 2, 3); // auto t = (1, 2, 3); // after DIP, the same thing as above writeln(t); // now: (1, 2, 3) before: Tuple!(int, int, int)(1, 2, 3)
 -----
 
 About proposal 2, you say it's inspired by the conversation we had in 
 the forums. I remember the discussion, but I'm not seeing the 
 relationship with Proposal 2.
 ...
Proposal 2 implements "these kind of allowances" in this post: https://forum.dlang.org/post/orink2$2lpr$1 digitalmars.com (The DIP does not go further than that, because: https://forum.dlang.org/post/or7sqd$dqg$1 digitalmars.com )
 I also am not sure about the example. It defines some function max, and 
 then never uses it.
Fixed. :) Thanks!
 I'm assuming somewhere there's a typo? In fact, I 
 think the example would compile today as it doesn't use any tuples (I 
 think), so I don't see the reason for it.
 
 -Steve
It uses tuples because it uses zip. The code does not compile today, because the lambda I'm passing to "map" has two parameters: auto a = [1, 2, 4, 7, 2]; auto b = [3, 5, 3, 2, 4]; // auto c = zip(a, b).map!((x, y) => x + y); // error auto c = zip(a, b).map!(t => t[0] + t[1]); // ok
Jan 16
next sibling parent Steven Schveighoffer <schveiguy yahoo.com> writes:
On 1/17/18 1:44 AM, Timon Gehr wrote:
 On 17.01.2018 02:20, Steven Schveighoffer wrote:
 On 1/12/18 5:44 PM, Timon Gehr wrote:
 As promised [1], I have started setting up a DIP to improve tuple 
 ergonomics in D:

 https://github.com/tgehr/DIPs/blob/tuple-syntax/DIPs/DIP1xxx-tg.md
Awesome! I can say I felt a lot more comfortable with the trailing-comma syntax after our last discussion :)
 Before going ahead with it, I'd like some preliminary community input:

 - I'm not yet completely satisfied with the DIP.
    (See section "Limitations".)
    Please let me know suggestions or further concerns you might have.
In the section discussing the breaking changes with proposal 3, you say: "The DIP author cannot see an obvious mitigation other than keeping std.typecons.Tuple and core.object.__Tuple separate instead of aliasing them." Well, what if std.typecons.Tuple can detect whether it's being used in a non-compatible way, and falls back on the original implementation? That is, when it works, it's an alias to object.__Tuple/__tuple, when it doesn't work, it's the old std.typecons.Tuple/tuple. I would expect it not to be that difficult to detect, but you don't specify exactly what the problems are so I'm not 100% sure I know what you are talking about :) An example would help. ...
The example is: auto t = tuple(1, 2, 3); // auto t = (1, 2, 3); // after DIP, the same thing as above writeln(t); // now: (1, 2, 3) before: Tuple!(int, int, int)(1, 2, 3)
OK, so writeln isn't going to show the type any more. This seems like a small difference, but possibly could affect code. I thought there was more of an issue with the actual construction of a tuple that wouldn't work with the new version.
 
 Proposal 2 implements "these kind of allowances" in this post:
 https://forum.dlang.org/post/orink2$2lpr$1 digitalmars.com
 
 (The DIP does not go further than that, because: 
 https://forum.dlang.org/post/or7sqd$dqg$1 digitalmars.com )
I'll have to re-read that whole discussion...
 It uses tuples because it uses zip. The code does not compile today, 
 because the lambda I'm passing to "map" has two parameters:
 
 auto a = [1, 2, 4, 7, 2];
 auto b = [3, 5, 3, 2, 4];
 
 // auto c = zip(a, b).map!((x, y) => x + y); // error
 
 auto c = zip(a, b).map!(t => t[0] + t[1]); // ok
Ah, ok, I see that now. I thought it worked because of the alias this :) Definitely, we need something like this. -Steve
Jan 17
prev sibling parent reply Nick Treleaven <nick geany.org> writes:
On Wednesday, 17 January 2018 at 06:44:21 UTC, Timon Gehr wrote:
 It uses tuples because it uses zip. The code does not compile 
 today, because the lambda I'm passing to "map" has two 
 parameters:

 auto a = [1, 2, 4, 7, 2];
 auto b = [3, 5, 3, 2, 4];

 // auto c = zip(a, b).map!((x, y) => x + y); // error

 auto c = zip(a, b).map!(t => t[0] + t[1]); // ok
We could make lambdas consistent with proposal 5: // Proposal 5: Unpacking function arguments void foo((int x, int y), int z){ writeln(x, " ", y, " ", z); } // lambda takes one tuple of two elements alias f = ((x, y)) => x + y; auto c = zip(a, b).map!f; // ok Is there a better example as to why a tuple decaying to function arguments is worth having vs the language complication?
Mar 15
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 15.03.2018 14:42, Nick Treleaven wrote:
 On Wednesday, 17 January 2018 at 06:44:21 UTC, Timon Gehr wrote:
 It uses tuples because it uses zip. The code does not compile today, 
 because the lambda I'm passing to "map" has two parameters:

 auto a = [1, 2, 4, 7, 2];
 auto b = [3, 5, 3, 2, 4];

 // auto c = zip(a, b).map!((x, y) => x + y); // error

 auto c = zip(a, b).map!(t => t[0] + t[1]); // ok
We could make lambdas consistent with proposal 5: ...
Good point. That's indeed the intention, but I didn't get around to updating the grammar section.
 ...
 // lambda takes one tuple of two elements
 alias f = ((x, y)) => x + y;
 auto c = zip(a, b).map!f; // ok
 
 Is there a better example as to why a tuple decaying to function 
 arguments is worth having vs the language complication?
Yes, but I don't think a better example is even needed. If you think ((x, y)) => x + y is tolerable, you are unlikely to be convinced by a better example. There's also the point that it is not unreasonable to expect that it already works when reading https://dlang.org/spec/class.html#alias-this.
Mar 15
parent Timon Gehr <timon.gehr gmx.ch> writes:
On 15.03.2018 17:14, Timon Gehr wrote:

 We could make lambdas consistent with proposal 5:
 ...
Good point. That's indeed the intention, but I didn't get around to updating the grammar section.
Nevermind, it's already there, as the grammar shares "Parameters" between functions and function literals (as it should).
May 02
prev sibling next sibling parent reply Manu <turkeyman gmail.com> writes:
On 12 January 2018 at 14:44, Timon Gehr via Digitalmars-d <
digitalmars-d puremagic.com> wrote:

 As promised [1], I have started setting up a DIP to improve tuple
 ergonomics in D:

 https://github.com/tgehr/DIPs/blob/tuple-syntax/DIPs/DIP1xxx-tg.md


 This DIP aims to make code like the following valid D:

 ---
 auto (a, b) = (1, 2);
 (int a, int b) = (1, 2);
 ---

 ---
 foreach((sum, diff); [(1, 2), (4, 3)].map!((a, b) => (a + b, a - b)))
 {
     writeln(sum, " ", diff);
 }
 /+ prints:
 3 -1
 7 1
 +/
 ---

 Before going ahead with it, I'd like some preliminary community input:

 - I'm not yet completely satisfied with the DIP.
   (See section "Limitations".)
   Please let me know suggestions or further concerns you might have.


 - There are good example use cases missing. While I'm confident I could
   invent a few of them given a little time, I thought maybe I can
   expedite the process and make the point more convincingly by asking
   for use cases you encountered in your own code. The DIP already
   contains an example due to bearophile.


 [1] https://forum.dlang.org/post/or625h$2hns$1 digitalmars.com
This is nice work! I hope this is seriously considered. I'll add my 2c... You discuss 'auto unpacking', can you justify the value of this? I quite like C++ explicit unpacking (using ...), and I wouldn't be upset to see that appear here too. Explicit unpacking would solve your breaking change with auto unpacking, but the buggest advantage of C++'s '...' statement is that the unpack can involve expressions. auto t = (1, 2, 3); f(t...); // <-- regular expansion: f(1, 2, 3); f(arr[t]...); // <-- expression expansion: f(arr[1], arr[2], arr[3]); etc... It's amazingly useful to perform tuple expansion on an expression involving the tuple! So, why might implicit expansion be preferred to explicit expansion?
Jan 17
next sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 17.01.2018 20:43, Manu wrote:
 On 12 January 2018 at 14:44, Timon Gehr via Digitalmars-d 
 <digitalmars-d puremagic.com <mailto:digitalmars-d puremagic.com>> wrote:
 
     As promised [1], I have started setting up a DIP to improve tuple
     ergonomics in D:
 
     https://github.com/tgehr/DIPs/blob/tuple-syntax/DIPs/DIP1xxx-tg.md
     ...
 
 
 This is nice work!
 I hope this is seriously considered.
 
 I'll add my 2c...
 You discuss 'auto unpacking', can you justify the value of this?
 ...
1. It exists already, and it seems inconsistent that it does not work for function calls: import std.typecons, std.meta, std.stdio; void main(){ AliasSeq!(int,int) t = tuple(1, 2); // auto-expanded with alias this writeln(t); // 12 int add(int a,int b){ return a + b; } writeln(add(tuple(1, 2))); // why _not_ auto-expanded with alias this? } 2. It's very useful in code that contains templates, for example ranges: [(1, 2), (3, 4), (5, 6)].map!((a, b) => a + b); At the moment, range code often gets a bit awkward, with indices all over the place, once tuples get involved, because the tuple components cannot be unpacked at the function call boundary. 3. I think it is a bit of a tragedy that the longest common substring of "(int a, int b) x;" and "void foo(int a, int b){}" does not have exactly the same interpretation for both, such that foo(x) is a perfect match. (The function declaration /looks like/ it declares a pattern that can be matched against by a tuple.) This cannot really be fixed, but auto-expansion removes the difference to the largest degree reasonably possible.
 I quite like C++ explicit unpacking (using ...), and I wouldn't be upset 
 to see that appear here too.
 Explicit unpacking would solve your breaking change with auto unpacking, 
It would also get rid of the feature I want. :-)
 but the buggest advantage of C++'s '...' statement is that the unpack 
 can involve expressions.
    auto t = (1, 2, 3);
    f(t...);          // <-- regular expansion: f(1, 2, 3);
    f(arr[t]...);    // <-- expression expansion: f(arr[1], arr[2], arr[3]);
 etc...
 
 It's amazingly useful to perform tuple expansion on an expression 
 involving the tuple!
 
 So, why might implicit expansion be preferred to explicit expansion?
1. The code that calls the function might not be your own code. It could be code that is operating on some generic type T, which you happened to instantiate with a tuple. This code wouldn't really know when to expand if not checking explicitly on each call. 2. The particular solution C++ has chosen lacks a bit of flexibility: It cannot distinguish between zipping and taking a Cartesian product in case more than one tuple is involved. 3. There is not actually a trade-off. We already have explicit expansion (the .expand property). The additional built-in C++ functionality, and more, can be easily supported in the library with standard range-like syntax: import std.range, std.string, std.algorithm, std.typecons, std.conv, std.stdio; int f(int a, int b, int c){ return a + b + c; } void main(){ auto t = tuple(1, 2, 3); writeln(f(t.expand)); // 6 auto arr = [0, 9, 4 ,3, 5]; writeln(f(t.map!(i=>arr[i]).expand)); // 16 } template map(alias f){ auto map(T...)(Tuple!T t){ return mixin(text("tuple(",std.algorithm.map!(i=>text("f(t[",i,"])"))(iota(t.length)).join(","),")")); } }
Jan 17
prev sibling parent Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Wednesday, 17 January 2018 at 19:43:03 UTC, Manu wrote:
 I quite like C++ explicit unpacking (using ...), and I wouldn't 
 be upset to
 see that appear here too.
FWIW C++17 has structured binding: http://en.cppreference.com/w/cpp/language/structured_binding auto [x,y] = f()
Jan 17
prev sibling next sibling parent Seb <seb wilzba.ch> writes:
On Friday, 12 January 2018 at 22:44:48 UTC, Timon Gehr wrote:
 As promised [1], I have started setting up a DIP to improve 
 tuple ergonomics in D:

 https://github.com/tgehr/DIPs/blob/tuple-syntax/DIPs/DIP1xxx-tg.md


 This DIP aims to make code like the following valid D:

 ---
 auto (a, b) = (1, 2);
 (int a, int b) = (1, 2);
 ---

 ---
 foreach((sum, diff); [(1, 2), (4, 3)].map!((a, b) => (a + b, a 
 - b)))
 {
     writeln(sum, " ", diff);
 }
 /+ prints:
 3 -1
 7 1
 +/
 ---

 Before going ahead with it, I'd like some preliminary community 
 input:

 - I'm not yet completely satisfied with the DIP.
   (See section "Limitations".)
   Please let me know suggestions or further concerns you might 
 have.


 - There are good example use cases missing. While I'm confident 
 I could
   invent a few of them given a little time, I thought maybe I 
 can
   expedite the process and make the point more convincingly by 
 asking
   for use cases you encountered in your own code. The DIP 
 already
   contains an example due to bearophile.


 [1] https://forum.dlang.org/post/or625h$2hns$1 digitalmars.com
My small contribution to this: https://github.com/dlang/dmd/pull/7813 https://github.com/dlang/dlang.org/pull/2151 Comma expressions will soon (2.079) be fully gone from the language and they can now finally be re-purposed for tuples.
Jan 30
prev sibling next sibling parent reply Martin Nowak <code+news.digitalmars dawg.eu> writes:
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA512

On 01/12/2018 11:44 PM, Timon Gehr wrote:
 As promised [1], I have started setting up a DIP to improve tuple 
 ergonomics in D:
 
 https://github.com/tgehr/DIPs/blob/tuple-syntax/DIPs/DIP1xxx-tg.md
Pardon me if things have been said already, can't really read through all the thread. - - Regarding underscore as placeholder. https://issues.dlang.org/show_bug.cgi?id=13522 - - Regarding the "limitation" Maybe you want some auto-packing feature there? Doesn't seem too bad, we could come up with sth. when this turns out to become a common nuisance. Have you considered to lower (1, 2, 3)[0 .. 2] to tuple(tuple(1, 2, 3)[0 .. 2]) or using a non-std.typecons tuple where slicing does not expand? - - closed tuples? The reference to std.typecons.tuple implies contiguous struct memory layout (closed tuples). This is a bit subtle for unpacking assignments which lower to AliasSeq!(x, y) = tuple(y, x)[]; so on the left-hand side of an assignment, the syntax refers to a non-contiguous (open) tuple. Declarations like auto (a, b) = (1, 2); also seem to declare an open tuple (non-contiguous memory). I assume that unpacking function arguments behaves similarly, i.e. on ABI level, each argument is passed separately. Overall looks really good. I think that would make for a great addition to the language. - -Martin -----BEGIN PGP SIGNATURE----- iQIzBAEBCgAdFiEEpzRNrTw0HqEtE8TmsnOBFhK7GTkFAlqHNkgACgkQsnOBFhK7 GTka+A/9HVHrawW5XyqzpGnT+qkyaG3a4dZdVvHbs9gJ0x7SHDyBgjKs576dW7g5 GEfGFjPkEZqKGvbtWgSicRV01qNmyGfVsgmWestK59niQAHLMUYx8PBsmeX/1CP9 MxLPMx9a0Z+h0D1z8sCLjHV5NcVZLziP3lnuUUvVXLUEv/gBZV52Eu++/iJmqKaj K9Boyv2+IrTTkv426PNxCy1iblMVi7B2bP44HErwij9+si8Zby3O8ExAh97MOBdH eoPT6TzmJxpExUfdiXcJ26HFxa4V8WhB/YaS50uYoUUYbaj0njtLwLyCkzUsjGzb JV32ZI7ncfHmMHCaJ09SGHfvh2dHKHa/VHU5ar3ivnzAXBLjdoe7MNi3QGH+zi6M U+RtY6WBkiVnYcLmanmMJKhyRsj3k3qT1I4zmVm6kbrs/oBqegtQcFoiQxm/DNMc LKLlNTEWuWIFquA6rd5OJ7kxhdbv5dE9vAgDNYcPP8GOB78sbZMQKxBTcI0a1EQC JYYvICiI9+CqjIeOU0F/LDv48JIk5BGSrh8m0cjwUtq4ivGEKo4V6Oc+1smsXmAo +XpSyyQi/t8pj037w0zSS0KA88qL4Fc4fvuujNnr5a9AkiV7zrMb9oyM00+F7cgo UApw3Lpr9g8GBKKu8HcbzGQMq86TYq/unSsD3ZFJEA3PCz8/5aY= =VB2T -----END PGP SIGNATURE-----
Feb 16
parent Timon Gehr <timon.gehr gmx.ch> writes:
On 16.02.2018 20:51, Martin Nowak wrote:
 -----BEGIN PGP SIGNED MESSAGE-----
 Hash: SHA512
 
 On 01/12/2018 11:44 PM, Timon Gehr wrote:
 As promised [1], I have started setting up a DIP to improve tuple
 ergonomics in D:

 https://github.com/tgehr/DIPs/blob/tuple-syntax/DIPs/DIP1xxx-tg.md
Pardon me if things have been said already, can't really read through all the thread. - - Regarding underscore as placeholder. https://issues.dlang.org/show_bug.cgi?id=13522
Thanks! I'll add a link to the enhancement to the DIP.
 - - Regarding the "limitation"
 
 Maybe you want some auto-packing feature there? Doesn't seem too bad,
 we could come up with sth. when this turns out to become a common
 nuisance.
 Have you considered to lower (1, 2, 3)[0 .. 2] to tuple(tuple(1, 2,
 3)[0 .. 2]) or using a non-std.typecons tuple where slicing does not
 expand?
 ...
I think this is technically a good idea, but there are drawbacks: (i) the language does not support this for user-defined types, ideally we avoid adding more built-in magic, and (ii) having two different types will be confusing to newcomers. ("Which of the two seemingly equivalent Tuple constructs should I use?")
 - - closed tuples?
 
 The reference to std.typecons.tuple implies contiguous struct memory
 layout (closed tuples).
 This is a bit subtle for unpacking assignments which lower to
 
 AliasSeq!(x, y) = tuple(y, x)[];
 
 so on the left-hand side of an assignment, the syntax refers to a
 non-contiguous (open) tuple.
 ...
I don't think this is the best way to think about it. Syntactically, the left-hand side contains two non-contiguous variables x and y and uses their values to form a contiguous tuple, but as it is the left-hand side of an assignment, the operation is actually performed in the opposite direction. This is a bit as if D supported assignments of the form: int a; a + 1 = 3; assert(a == 2); // computed using the inverse: a = 3 - 1 Of course, this is independent of the actual implementation strategy chosen.
 Declarations like
 
 auto (a, b) = (1, 2);
 
 also seem to declare an open tuple (non-contiguous memory).
 ...
Yes, the idea is that this would declare multiple independent variables.
 I assume that unpacking function arguments behaves similarly, i.e. on
 ABI level, each argument is passed separately.
 ...
I think the ABI should be unaffected in this case (it is just syntax sugar for unpacking the tuple argument immediately at the start of the called function, i.e. it is a callee-site construct that happens to sometimes make the signature prettier for the caller also). I will clarify this point.
 
 Overall looks really good. I think that would make for a great
 addition to the language.
 ...
Thanks! I'll make sure to incorporate your points when I'll finally get around to updating the DIP based on the forum feedback.
Feb 16
prev sibling next sibling parent reply timotheecour <timothee.cour2 gmail.com> writes:
On Friday, 12 January 2018 at 22:44:48 UTC, Timon Gehr wrote:
 As promised [1], I have started setting up a DIP to improve 
 tuple ergonomics in D:

 https://github.com/tgehr/DIPs/blob/tuple-syntax/DIPs/DIP1xxx-tg.md


 This DIP aims to make code like the following valid D:
... Would this DIP allow array unpacking? eg, see this rust snippet from https://gist.github.com/anonymous/9cfc3d1b057f7a137ccbfb94bf4bfcef ``` fn main() { let (infile, colname, repl, outfile) = std::env::args().skip(1).tuples().next().expect("Invalid args\n"); } ``` what would be the D equivalent under this DIP? (just for the array unpacking part )
Feb 19
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 20.02.2018 00:19, timotheecour wrote:
 On Friday, 12 January 2018 at 22:44:48 UTC, Timon Gehr wrote:
 As promised [1], I have started setting up a DIP to improve tuple 
 ergonomics in D:

 https://github.com/tgehr/DIPs/blob/tuple-syntax/DIPs/DIP1xxx-tg.md


 This DIP aims to make code like the following valid D:
... Would this DIP allow array unpacking? ...
Yes, but would not be built-in.
 eg, see this rust snippet from 
 https://gist.github.com/anonymous/9cfc3d1b057f7a137ccbfb94bf4bfcef
 
 ```
 fn main() {
    let (infile, colname, repl, outfile) = 
 std::env::args().skip(1).tuples().next().expect("Invalid args\n");
 }
 ```
 
 what would be the D equivalent under this DIP? (just for the array 
 unpacking part )
 
 
 
For a suitable implementation of "unpack": void main(){ auto (infile, colname, repl, outfile) = args[1..$].unpack!4("Invalid args\n"); } Unfortunately, there is no good way to get rid of "4", as D does not have backwards type inference.
Feb 19
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 20.02.2018 00:43, Timon Gehr wrote:
 
 void main(){
      auto (infile, colname, repl, outfile) = 
 args[1..$].unpack!4("Invalid args\n");
 }
Actually: void main(string[] args){ auto (infile, colname, repl, outfile) = args[1..$].unpack!4("Invalid args\n"); }
Feb 19
parent reply Timothee Cour <thelastmammoth gmail.com> writes:
great! maybe worth adding to DIP? (even though `unpack` would be
(IIUC) a pure library solution on top of this DIP)

and that would work too I guess?
```
string[4] args=...;
auto (infile, colname, repl, outfile) = args.unpack;
```


On Mon, Feb 19, 2018 at 3:47 PM, Timon Gehr via Digitalmars-d
<digitalmars-d puremagic.com> wrote:
 On 20.02.2018 00:43, Timon Gehr wrote:
 void main(){
      auto (infile, colname, repl, outfile) = args[1..$].unpack!4("Invalid
 args\n");
 }
Actually: void main(string[] args){ auto (infile, colname, repl, outfile) = args[1..$].unpack!4("Invalid args\n"); }
Feb 19
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 20.02.2018 00:53, Timothee Cour wrote:
 great! maybe worth adding to DIP? (even though `unpack` would be
 (IIUC) a pure library solution on top of this DIP)
 ...
Yes. I'll add it to the use cases.
 and that would work too I guess?
 ```
 string[4] args=...;
 auto (infile, colname, repl, outfile) = args.unpack;
 ```
Sure! Also, this: void main(string[] args){ enforce(args.length==5, "Invalid args"); auto (infile, colname, repl, outfile) = args[1..5].unpack; // ... }
Feb 19
parent reply Timothee Cour <thelastmammoth gmail.com> writes:
On Mon, Feb 19, 2018 at 4:05 PM, Timon Gehr via Digitalmars-d
<digitalmars-d puremagic.com> wrote:
 On 20.02.2018 00:53, Timothee Cour wrote:

 Sure! Also, this:

 void main(string[] args){
     enforce(args.length==5, "Invalid args");
     auto (infile, colname, repl, outfile) = args[1..5].unpack;
     // ...
 }
how does that latter example work?
Feb 19
parent Timon Gehr <timon.gehr gmx.ch> writes:
On 20.02.2018 01:57, Timothee Cour wrote:
 On Mon, Feb 19, 2018 at 4:05 PM, Timon Gehr via Digitalmars-d
 <digitalmars-d puremagic.com> wrote:
 On 20.02.2018 00:53, Timothee Cour wrote:

 Sure! Also, this:

 void main(string[] args){
      enforce(args.length==5, "Invalid args");
      auto (infile, colname, repl, outfile) = args[1..5].unpack;
      // ...
 }
how does that latter example work?
IFTI. unpack could have the following overload: auto unpack(size_t n,T)(T[n] args){ return mixin("tuple("~iota(n).map!(i=>text("args[",i,"]")).join(",")~")"); }
Feb 19
prev sibling next sibling parent reply ixid <nuaccount gmail.com> writes:
On Friday, 12 January 2018 at 22:44:48 UTC, Timon Gehr wrote:
 auto (a, b) = (1, 2);
For the assignment and unpacking grammar why not adopt the more streamlined Go syntax? auto a, b = 1, 2; // Creates two new variables with the values 1 and 2 auto c, d = 1, (2,3); // A normal variable and a tuple This would seem a lot clearer than: auto (a, b) = (1,2); auto (c, d) = (1, (2,3));
Mar 15
parent Timon Gehr <timon.gehr gmx.ch> writes:
On 15.03.2018 11:45, ixid wrote:
 On Friday, 12 January 2018 at 22:44:48 UTC, Timon Gehr wrote:
 auto (a, b) = (1, 2);
For the assignment and unpacking grammar why not adopt [...] Go syntax? ...
It does not fit in.
 auto a, b = 1, 2; // Creates two new variables with the values 1 and 2
 auto c, d = 1, (2,3); // A normal variable and a tuple
 ...
For this use case, there is already this: auto a = 1, b = 2; auto c = 1, d = (2, 3); Under your proposal, this would now suddenly parse as: auto a = ((1, b) = 2); auto c = ((1, d) = (2, 3));
Mar 15
prev sibling parent reply JN <666total wp.pl> writes:
On Friday, 12 January 2018 at 22:44:48 UTC, Timon Gehr wrote:
 As promised [1], I have started setting up a DIP to improve 
 tuple ergonomics in D:

 https://github.com/tgehr/DIPs/blob/tuple-syntax/DIPs/DIP1xxx-tg.md
I may be out of the loop here, but what is the actual usecase for tuples? What benefits does it bring? Isn't stuff like auto a, b = func() less clean than using structs, e.g. FuncResult ab = func() ?
Mar 15
parent reply Stefan Koch <uplink.coder googlemail.com> writes:
On Thursday, 15 March 2018 at 14:07:12 UTC, JN wrote:
 On Friday, 12 January 2018 at 22:44:48 UTC, Timon Gehr wrote:
 As promised [1], I have started setting up a DIP to improve 
 tuple ergonomics in D:

 https://github.com/tgehr/DIPs/blob/tuple-syntax/DIPs/DIP1xxx-tg.md
I may be out of the loop here, but what is the actual usecase for tuples? What benefits does it bring? Isn't stuff like auto a, b = func() less clean than using structs, e.g. FuncResult ab = func() ?
For example you can have optional return-values. And you don't introduce a dependency of the definition of a particular type. Also you can write the elemets of the tuple direct into instance of a different type, without the need of creating a temporary. That said, I am not sure if I would be willing to pay the complexity cost for it.
Mar 15
parent Seb <seb wilzba.ch> writes:
On Thursday, 15 March 2018 at 14:11:47 UTC, Stefan Koch wrote:
 On Thursday, 15 March 2018 at 14:07:12 UTC, JN wrote:
 On Friday, 12 January 2018 at 22:44:48 UTC, Timon Gehr wrote:
 As promised [1], I have started setting up a DIP to improve 
 tuple ergonomics in D:

 https://github.com/tgehr/DIPs/blob/tuple-syntax/DIPs/DIP1xxx-tg.md
I may be out of the loop here, but what is the actual usecase for tuples? What benefits does it bring? Isn't stuff like auto a, b = func() less clean than using structs, e.g. FuncResult ab = func() ?
For example you can have optional return-values. And you don't introduce a dependency of the definition of a particular type. Also you can write the elemets of the tuple direct into instance of a different type, without the need of creating a temporary. That said, I am not sure if I would be willing to pay the complexity cost for it.
Tuples was by far the most missed language feature in the "State of D" survey: https://rawgit.com/wilzbach/state-of-d/master/report.html#180373345 (50% of all respondents mentioned tuples as a language feature they miss in D.)
Mar 15