January 16, 2018
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.
January 16, 2018
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.
January 16, 2018
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.
January 17, 2018
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?

January 16, 2018
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
January 17, 2018
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
January 17, 2018
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
January 17, 2018
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!


January 17, 2018
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?


January 17, 2018
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(","),")"));
    }
}