March 29, 2013
2013/3/29 bearophile <bearophileHUGS@lycos.com>

> One handy tuple syntax in Haskell allows you to name both the items of a tuple and it whole:
>
> void foo(t2@{int a, string b}) {
>    // here a and b are tuple items and t2 is the whole tuple.
> }
> auto t1@{x, y} = {10, "hi"};
> foo(t1);
>

It will introduce a kind of "reference variable" to D.

auto t1@{x, y} = {10, "hi"};
assert(&t1[0] == &x);
// t1[0] and x may refer same address on stack.

Such case, you can repeat pack and unpack.

void foo({int a, string b}) {
   // auto t2 = {a, b};  // make tuple by copy, or
   // {a, b} = {1, 2};    // make pack and use it immediately
}
auto {x, y} = {10, "hi"};  foo({x, y});


> auto tup = {};  // zero-element tuple (Syntax meaning will be changed!)
>
> Nullary tuples are not that useful in D. Scala doesn't even have a short literal for them.
>
> So a longer syntax like this is acceptable:
>
> auto tup = Tuple();
>

This is for the consistency of language elements.
If you want to zero-parameter lambda, you can write like follows.

auto fn = (){};
auto fn = {;};


> - - - - - - - - - - - -
>
> This is nice, so we are merging tuple types with tuples, this will simplify D language:
>
> // declare tuple value by using explicit tuple type
> {int, string} tup = {1, "hi"};
>
>  alias TL = {int, string[], double[string]};  // types
>
>
> But one thing to remember in the document is that here T1 and T2 are different, because your tuples do not auto-flatten as TypeTuples currently do:
>
> alias T1 = {float, double, real};
> alias T2 = {float, double, {real}};
>

It would need more description. I'll explain about that.

- - - - - - - - - - - -
>
> foreach (Float; {float, double, real}) { ... }
>
> I think you meant to put a variable name there.
>

Float is the iterated type.


> - - - - - - - - - - - -
>
>     {1}         // one-element tuple
>
> I presume this too will be accepted as 1-tuple:
>
>     {1,}
>

Currently D allows redundant commas in some places.
void foo(int x, int y,) {}
enum E { a = 1, b = 2, }
auto arr = [1,2,3,];

So, compiler would accept following tuples.

auto tup = {1,};
auto tup = {1,"hi",};


> - - - - - - - - - - - -
>
> {c, $} = tup;   // Rewritten as: c = tup[0];
>
> $ is used for array lengths, so it's not so good to overload it to mean "don't care" too.
>
> Alternative syntaxes:
>
> {c, $_} = tup;
> {c, @} = tup;
> {c, @_} = tup;
> {c, $$} = tup;
> {c, {}} = tup;
> {c, {_}} = tup;
> {c, $~} = tup;
> {c, @~= tup;
> etc.
>

Placeholder token is debatable.


> - - - - - - - - - - - -
>
>
> if (auto {1, y} = tup) {
>     // If the first element of tup (tup[0]) is equal to 1,
>     // y captures the second element of tup (tup[1]).
> }
>
>
> I suggest to leave that pattern matching plus conditional to a future refinement of tuple implementation (a second stage. And remove it from this first stage proposal. So I suggest to split your proposal in two successive proposals). It seems handy, but D programmers need some time to go there.
>

For complex tuple unpacking requires the part of pattern matching.

auto tup = {1, {2,3,4,5,6}}
auto {x, {$, y, ...}} = tup;   // makes nested tuple pattern for unpacking
assert(x == 1);
assert(y == 3);

So I'd like to keep one DIP.


> - - - - - - - - - - - -
>
> switch (tup) {
>     case {1, 2}:
>     case {$, 2}:
>     case {1, x}:    // capture tup[1] into 'x' when tup[0] == 1
>     default:        // same as {...}
> }
>
>
> What's quite important here is the "final switch". D has to make sure you are considering all possible cases.
>
> - - - - - - - - - - - -
>
> I suggest to leave this to the second stage, and remove it from this proposal:
>
> auto tup = {1, "hi", 3.14, [1,2,3]};
> if (auto {1, "hi", ...} = tup) {}
>
> - - - - - - - - - - - -
>
> "will" is written badly:
>
>
> // If the first element of coord is equal to 1 (== x), 'then' statement
> wil be evaluated.
>

Will fix.


> - - - - - - - - - - - -
>
> I think this is the third thing to leave to the second stage:
>
> int x = 1;
> if (auto {$x, y} = coord) { ... }
>
> - - - - - - - - - - - -
>
> This is nice:
>
> if (auto {x, y} = coord[]) {}   // same, explicitly expands fields
>
> - - - - - - - - - - - -
>
> This is handy and it's vaguely present in Python3, but I suggest to leave this (4th thing) to the second stage:
>
> if (auto {num, msg, ...} = tup) {}      // ok, `...` matches to
> zero-elements.
>

Kenji Hara


March 29, 2013
kenji hara:

> For tuple values with named fields, we need more thoughts about semantics.
>
> alias MyPair = typeof({1, "hi"});
> alias MyRecord = typeof({count:1, msg:"hi"});
> static assert(is(MyPair == MyRecord));  // true or false?
> static assert(is(MyPair  : MyRecord));  // true or false?
> static assert(is(MyRecord  : MyPair));  // true or false?
> alias MyStudent = typeof({num:1, name:"John"});
> static assert(is(MyRecord == MyStudent));  // true or false?

One solution:
http://en.wikipedia.org/wiki/Covariance_and_contravariance_%28computer_science%29

{count:1, "hi"} and {1, msg:"hi"} are invariant.

{count:1, msg:"hi"}, {count:1, "hi"} and {1, msg:"hi"} are covariant to {1, "hi"}.

But I think it's better to leave this to the Stage2.

Bye,
bearophile
March 29, 2013
2013/3/29 Timon Gehr <timon.gehr@gmx.ch>

> Looks quite nice. I especially like the {a, b} => ... thing.
>
> I think, however, that there are a handful serious flaws that need to be addressed:
>
> 0 "Inside tuple literal, ; never appears."
>   {{;}}           // a tuple not matching your specification
>

It will be parsed as:
{     // tuple braces
    {;}   // function literal braces
}


>   {{if(foo()){}}} // a non-tuple matching your specification
>

{    // tuple braces
    {    // function literal braces
        if (foo()){}   // "if" always appears in statement scope
    }
}


> 1 "Note: Cannot swap values by tuple assignment."
>   IMO a no-go. The syntax is too accessible to introduce this kind of
>   pitfall.
>

Allowing value swap in tuple assignment will make language complex. I can't agree with it.


> 2 "// Error: cannnot use $ inside a function literal"
>   That's a DMD-ism presumably stemming from laziness during "fixing" of
>   an ICE/wrong code bug or something. I'd hate to carry this over to
>   the spec. Don't rely on it. The disambiguation is arbitrary, but may
>   be necessary. (It's not like it is a case actually occurring in real
>   code.)
>
> 3 Unpacking / pattern matching is underspecified.
>   - Do patterns nest?
>

I think it should be allowed.


>   - Which right-hand sides are allowed with which semantics?
>

Whether it is a pattern or a tuple-literal, is distinguished by their appeared locations.


>   - Which left-hand sides are allowed with which semantics?
>     eg, what about:
>       ref int foo() { ... }
>       { foo(), foo() } = {1, 2};
>

It will be lowered to:
// { foo(), foo() } = {1, 2};
foo() = 1;
foo() = 2;


> 4 There is no way to capture the part matched by "..."
>

I think this should be allowed.

auto {x, r...} = tup;
// Lowered to:
// auto x = tup[0];
// auto r = tup[1..$]

`...` is very consistent token for this purpose.

template X(T...) {}
alias x = X!(int, long);  // T captures {int, long}


> 5 .expand (or similar) property is missing.
>

Use tup[]. It is already exists.


> 6 Relation to {a: 2, b: 3}-style struct literals not explained.
>

I am skeptical of the necessity of tuple literal with named fields.

7 Tuple unpacking for template parameters not mentioned.
>
>
> Is there a migration path for Phobos tuples planned?
>
> Eg. template Tuple(T...){ alias Tuple = {T}; }
>     (field spec parsing left out for illustration)
>

Kenji Hara


March 29, 2013
On 03/29/2013 04:32 PM, kenji hara wrote:
> 2013/3/29 Timon Gehr <timon.gehr@gmx.ch <mailto:timon.gehr@gmx.ch>>
>
>     Looks quite nice. I especially like the {a, b} => ... thing.
>
>     I think, however, that there are a handful serious flaws that need
>     to be addressed:
>
>     0 "Inside tuple literal, ; never appears."
>        {{;}}           // a tuple not matching your specification
>
>
> It will be parsed as:
> {     // tuple braces

It contains ';', therefore the DIP says it is a function literal brace.

>      {;}   // function literal braces
> }
>
>        {{if(foo()){}}} // a non-tuple matching your specification
>
>
> {    // tuple braces
>      {    // function literal braces

There is no ';', therefore the DIP says it is a tuple brace.

>          if (foo()){}   // "if" always appears in statement scope
>      }
> }
>

I know how it _should_ be. The DIP contradicts what you say.

>     1 "Note: Cannot swap values by tuple assignment."
>        IMO a no-go. The syntax is too accessible to introduce this kind of
>        pitfall.
>
>
> Allowing value swap in tuple assignment will make language complex. I
> can't agree with it.
>

Quite obviously it is the other way round. There will be a never-ending flood of d.D.learn posts on the topic.

>     2 "// Error: cannnot use $ inside a function literal"
>        That's a DMD-ism presumably stemming from laziness during "fixing" of
>        an ICE/wrong code bug or something. I'd hate to carry this over to
>        the spec. Don't rely on it. The disambiguation is arbitrary, but may
>        be necessary. (It's not like it is a case actually occurring in real
>        code.)
>
>     3 Unpacking / pattern matching is underspecified.
>        - Do patterns nest?
>
>
> I think it should be allowed.
>

ok.

>        - Which right-hand sides are allowed with which semantics?
>
>
> Whether it is a pattern or a tuple-literal, is distinguished by their
> appeared locations.
>

Obviously, but this statement is not related to my question.
Valid right-hand sides seem to be at least tuples and expanded tuples (sequences). Anything else?


>        - Which left-hand sides are allowed with which semantics?
>          eg, what about:
>            ref int foo() { ... }
>            { foo(), foo() } = {1, 2};
>
>
> It will be lowered to:
> // { foo(), foo() } = {1, 2};
> foo() = 1;
> foo() = 2;
>

ok.

>     4 There is no way to capture the part matched by "..."
>
>
> I think this should be allowed.
>
> auto {x, r...} = tup;
> // Lowered to:
> // auto x = tup[0];
> // auto r = tup[1..$]
>
> `...` is very consistent token for this purpose.
>

Questionable.

> template X(T...) {}
> alias x = X!(int, long);  // T captures {int, long}
>

Not really. T captures {int, long}.expand.

>     5 .expand (or similar) property is missing.
>
>
> Use tup[]. It is already exists.
>

Slicing obviously shouldn't auto-expand. It's a shortcoming of the Phobos tuple introduced because static slicing cannot be overloaded.

>     6 Relation to {a: 2, b: 3}-style struct literals not explained.
>
>
> I am skeptical of the necessity of tuple literal with named fields.
>

Sure, but you'd at least have to argue in the DIP that the parser can distinguish the two, and how.

>     7 Tuple unpacking for template parameters not mentioned.
>
>
>     Is there a migration path for Phobos tuples planned?
>
>     Eg. template Tuple(T...){ alias Tuple = {T}; }
>          (field spec parsing left out for illustration)
>
>...

You have not answered the last two points.


March 29, 2013
kenji hara:

>> 5 .expand (or similar) property is missing.
>>
>
> Use tup[]. It is already exists.

You are right, I didn't know/remember about that:


import std.typecons;
void foo(int, int) {}
void main() {
    auto t = tuple(1, 2);
    foo(t.tupleof);
    foo(t[]);
    auto t2 = tuple(1, 2, 3);
    foo(t2[0 .. 2]);
}


But I don't like that. t2[0 .. 2] should return a new tuple that contains just the first two items. And like every one tuple it's not supposed to auto-unpack. So I think this is a design mistake that should be fixed in the new tuples.

Bye,
bearophile
March 29, 2013
On 2013-03-29 13:49, Adam D. Ruppe wrote:
> My first thought when I saw {} was json. This is getting a little
> further away from tuples, but would it be hard to add named fields to
> this too like json:
>
> auto a = {"foo":12, "bar":"twelve"};
>
> int a_foo = a.foo;
> string a_bar = a[1];

I had a proposal of anonymous structs that is similar to this:

http://forum.dlang.org/thread/kfbnuc$1cro$1@digitalmars.com

-- 
/Jacob Carlborg
March 29, 2013
On 2013-03-29 14:26, Timon Gehr wrote:

> Remove the quotes and it looks like a struct literal.
>
> I think if named fields are allowed, it should look as follows:
>
> auto a = {foo: 12, bar: "twelve"};

I agree.

-- 
/Jacob Carlborg
March 29, 2013
2013/3/30 Timon Gehr <timon.gehr@gmx.ch>

> On 03/29/2013 04:32 PM, kenji hara wrote:
>
>> 2013/3/29 Timon Gehr <timon.gehr@gmx.ch <mailto:timon.gehr@gmx.ch>>
>> It will be parsed as:
>> {     // tuple braces
>>
>
> It contains ';', therefore the DIP says it is a function literal brace.
>
>       {;}   // function literal braces
>>
>> }
>>
>>        {{if(foo()){}}} // a non-tuple matching your specification
>>
>>
>> {    // tuple braces
>>      {    // function literal braces
>>
>
> There is no ';', therefore the DIP says it is a tuple brace.
>
>
>           if (foo()){}   // "if" always appears in statement scope
>>      }
>> }
>>
>>
> I know how it _should_ be. The DIP contradicts what you say.
>

Sorry my incomplete description and poor English. I'll improve description in DIP.


> Allowing value swap in tuple assignment will make language complex. I
>> can't agree with it.
>>
>
> Quite obviously it is the other way round. There will be a never-ending flood of d.D.learn posts on the topic.
>

Yes, I agree with it. But, I won't change my opinion. So I'll stop talking about that.


>         - Which right-hand sides are allowed with which semantics?
>>
>>
>> Whether it is a pattern or a tuple-literal, is distinguished by their appeared locations.
>>
>
> Obviously, but this statement is not related to my question.
> Valid right-hand sides seem to be at least tuples and expanded tuples
> (sequences). Anything else?
>

Sorry I don't understand you question.

     4 There is no way to capture the part matched by "..."
>>
>>
>> I think this should be allowed.
>>
>> auto {x, r...} = tup;
>> // Lowered to:
>> // auto x = tup[0];
>> // auto r = tup[1..$]
>>
>> `...` is very consistent token for this purpose.
>>
>
> Questionable.
>
>  template X(T...) {}
>> alias x = X!(int, long);  // T captures {int, long}
>>
>>
> Not really. T captures {int, long}.expand.
>
>      5 .expand (or similar) property is missing.
>>
>>
>> Use tup[]. It is already exists.
>>
>
> Slicing obviously shouldn't auto-expand. It's a shortcoming of the Phobos tuple introduced because static slicing cannot be overloaded.
>

I think it will become reasonable. If you really want re-packing tuple, you can use {tup[0..1]}. It's quite handy.

     6 Relation to {a: 2, b: 3}-style struct literals not explained.
>>
>>
>> I am skeptical of the necessity of tuple literal with named fields.
>>
>>
> Sure, but you'd at least have to argue in the DIP that the parser can distinguish the two, and how.
>
>      7 Tuple unpacking for template parameters not mentioned.
>>
>
Will add description about it.

    Is there a migration path for Phobos tuples planned?
>>
>>     Eg. template Tuple(T...){ alias Tuple = {T}; }
>>          (field spec parsing left out for illustration)
>>
>
I have no plan.

Kenji Hara


March 29, 2013
kenji hara:

> I think it will become reasonable. If you really want re-packing tuple, you
> can use {tup[0..1]}. It's quite handy.

This is a bad idea. It is not handy and it introduces a special case. Explicit is better than implicit.

Bye,
bearophile
March 29, 2013
2013/3/30 bearophile <bearophileHUGS@lycos.com>

> kenji hara:
>
>
>  I think it will become reasonable. If you really want re-packing tuple,
>> you
>> can use {tup[0..1]}. It's quite handy.
>>
>
> This is a bad idea. It is not handy and it introduces a special case. Explicit is better than implicit.
>

That is "explicit". In D, opened tuple (currently it's generated from
template parameters, e.g. std.typetuple.TypeTuple) and closed tuple
(currently created by structs with alias tuple_field this; e.g.
std.typecons.Tuple) are distinct. Slice operator always returns opened
tuple.
If tup[0..1] makes closed tuple implicitly, you cannot make new flattened
tuple from other tuples.

auto x = {1,"hi"};
auto y = {[1,2], S(1)};
auto tup1 = {x[], y[]};   // creates {1,"hi", [1,2], S(1)}
auto tup2 = {x, y};   // creates {{1,"hi"}, {[1,2], S(1)}}

Under your semantics, it is impossible.

Kenji Hara.