January 04, 2022
On 04/01/2022 4:11 PM, Timon Gehr wrote:
> (I understand that there is something in the DMD source code already named "Tuple", but that's not really a tuple, it's a sequence of values that will auto expand into any context. Being able to return that from functions would be nice, but I think it's independent of what people are talking about when they want tuples.)

Actually this is kinda what I want.

Remove array, AA definitions in syntax. All you have is a tuple.

A tuple accepts both named and unnamed types or values.

It can devolve into static arrays, associative arrays, dynamic arrays all implicitly.
January 04, 2022
On 29.12.21 06:09, Walter Bright wrote:
> On 11/9/2021 11:09 PM, Timon Gehr wrote:
>> On 10/16/21 1:12 AM, Walter Bright wrote:
>>> On 10/12/2021 2:38 PM, Timon Gehr wrote:
>>>> - non-lexical variable lifetimes (probably not happening)
>>>
>>> It's already implemented for @live.
>>
>>
>> Specifically, I would like it to influence scoping.
>>
>> ```d
>> int x=2;
>> int y=move(x);
>> int z=x; // error: undefined identifier x (was moved away)
> 
> @live currently does that for pointers, but not for non-pointers.

It removes the variable from the scope? (And anyway, @live is a function annotation, which makes little sense.)

> What's the use case for it?
> ...

This is just how moving things works. If you move it, it's no longer where it was. If the variable disappears, we don't have to bother with putting `x` into some safe default state. Some types can't even naturally support a safe default state. The simplest example is indeed a `struct` implementing a unique non-null pointer managing its own memory. (By whatever means you want, it does not even have to have any pointer members to implement such semantics.)

> 
>> int y=move(y); // ok
>> ```
> 
> I see what you mean, but since D disallows:
> 
>      int x; { int x; }
> 
> which prevents a number of bugs, so I can't see allowing that.

I don't see how that's related. It's two variables `y` whose lifetimes do not overlap. It's more like this:

{int x; } { int x; }

Which D allows.
January 04, 2022
On 04.01.22 05:20, rikki cattermole wrote:
> 
> On 04/01/2022 4:11 PM, Timon Gehr wrote:
>> (I understand that there is something in the DMD source code already named "Tuple", but that's not really a tuple, it's a sequence of values that will auto expand into any context. Being able to return that from functions would be nice, but I think it's independent of what people are talking about when they want tuples.)
> 
> Actually this is kinda what I want.
> 
> Remove array, AA definitions in syntax. All you have is a tuple.
> 
> A tuple accepts both named and unnamed types or values.
> 
> It can devolve into static arrays, associative arrays, dynamic arrays all implicitly.

My point was not that you don't want this, it was that calling it a "tuple" serves only to confuse.
January 04, 2022
On 04.01.22 06:14, Timon Gehr wrote:
> On 04.01.22 05:20, rikki cattermole wrote:
>>
>> On 04/01/2022 4:11 PM, Timon Gehr wrote:
>>> (I understand that there is something in the DMD source code already named "Tuple", but that's not really a tuple, it's a sequence of values that will auto expand into any context. Being able to return that from functions would be nice, but I think it's independent of what people are talking about when they want tuples.)
>>
>> Actually this is kinda what I want.
>>
>> Remove array, AA definitions in syntax. All you have is a tuple.
>>
>> A tuple accepts both named and unnamed types or values.
>>
>> It can devolve into static arrays, associative arrays, dynamic arrays all implicitly.
> 
> My point was not that you don't want this, it was that calling it a "tuple" serves only to confuse.

(Also, having only the expanding variety of this is just not very useful as it prevents nesting.)
January 03, 2022
On 1/3/2022 6:06 PM, Timon Gehr wrote:
> On 03.01.22 10:27, Walter Bright wrote:
>> On 1/2/2022 11:42 PM, Timon Gehr wrote:
>>> And there is also this:
>>>
>>> void foo(T...)(T args){}
>>>
>>> int[2] x;
>>>
>>> foo(x); // foo!(int[2]) and foo!(int,int) would now need to be the same
>>
>> With such implicit conversions, the language would just descend into chaos. So no :-)
> 
> It's not an implicit conversion.

Looks like it to me!

> I am mostly trying to figure out what constitutes "unification" for you. (In the programming languages I built, `int×int` and `int^2` are literally the same type, there is subtyping, but all actual type conversions are explicit.)
> 
> Personally, the single thing I care most about in terms of "unification" is that this works:
> 
> void foo(int a,int b){}
> (int,int) t;
> foo(t); // ok, function expects (int,int), and (int,int) was given
> 
> But *not* this:
> 
> void foo((int,int) a,int b){}
> 
> (int,int,int) t;
> foo(t); // error, function expects ((int,int),int), not (int,int,int)
> 
> I do not care much about `is((int,int)==int[2])`, but when you say you want to unify tuples and static arrays, that's what I think of.

That isn't what I meant. I mean that there are easy ways to convert from one to the other, but not implicit conversions.
January 04, 2022
On 04.01.22 06:40, Walter Bright wrote:
> On 1/3/2022 6:06 PM, Timon Gehr wrote:
>> On 03.01.22 10:27, Walter Bright wrote:
>>> On 1/2/2022 11:42 PM, Timon Gehr wrote:
>>>> And there is also this:
>>>>
>>>> void foo(T...)(T args){}
>>>>
>>>> int[2] x;
>>>>
>>>> foo(x); // foo!(int[2]) and foo!(int,int) would now need to be the same
>>>
>>> With such implicit conversions, the language would just descend into chaos. So no :-)
>>
>> It's not an implicit conversion.
> 
> Looks like it to me!
> ...

If `foo(int, int)` is defined to be literally the same as `foo(int[2])`, there is no conversion. But anyway, I guess you'd also consider anything that would make this work an "implicit conversion"?

double foo(int x,string y);

writeln([(1,"2"),(1,"3"),(3,"4")].map!foo);

If so, maybe one way to make _some_ progress on this is to have a DIP specifically for destructuring, without adding any new types?
January 03, 2022
On 1/3/2022 10:37 PM, Timon Gehr wrote:
> If `foo(int, int)` is defined to be literally the same as `foo(int[2])`, there is no conversion. But anyway, I guess you'd also consider anything that would make this work an "implicit conversion"?
> 
> double foo(int x,string y);
> 
> writeln([(1,"2"),(1,"3"),(3,"4")].map!foo);

Currently, tuples can map right on to argument lists, there is no conversion. This works because a tuple in D isn't really a type at all. It's just a collection of expressions.


> If so, maybe one way to make _some_ progress on this is to have a DIP specifically for destructuring, without adding any new types?

I'm not sure what destructuring, but yes, not adding new types.
January 04, 2022
On Tuesday, 4 January 2022 at 07:52:00 UTC, Walter Bright wrote:
>> If so, maybe one way to make _some_ progress on this is to have a DIP specifically for destructuring, without adding any new types?
>
> I'm not sure what destructuring, but yes, not adding new types.

"Destructuring" means binding members of a tuple to separate variables; e.g.,

    struct S { int x; string y; }
    auto (x, y) = S(123, "hello").tupleof;
    assert(x == 123 && y == "hello");

C++17 has something similar, which it calls "structured bindings": https://en.cppreference.com/w/cpp/language/structured_binding
January 05, 2022
On 04.01.22 08:52, Walter Bright wrote:
> On 1/3/2022 10:37 PM, Timon Gehr wrote:
>> If `foo(int, int)` is defined to be literally the same as `foo(int[2])`, there is no conversion. But anyway, I guess you'd also consider anything that would make this work an "implicit conversion"?
>>
>> double foo(int x,string y);
>>
>> writeln([(1,"2"),(1,"3"),(3,"4")].map!foo);
> 
> Currently, tuples can map right on to argument lists, there is no conversion. This works because a tuple in D isn't really a type at all. It's just a collection of expressions.
> ...

But in the example above, those so-called "tuples" would expand right into the array literal and cause an error due to incompatible types. This can't work if `(1,"2")` etc. auto-expand. Furthermore, to put them into an array, they need to have an address.

> 
>> If so, maybe one way to make _some_ progress on this is to have a DIP specifically for destructuring, without adding any new types?
> 
> I'm not sure what destructuring,

Currently working with tuples (including actual tuples that are actual expressions, e.g., Phobos tuples) is inconvenient mostly (but not only) because you can't easily expand them into multiple named variables.

```d
auto (col1, col2) = table.query!((ref row)=>tuple(row.column1,row.column2))(key);
```

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

Proof-of-concept implementation here:
https://github.com/tgehr/dmd/commit/8ad53b0891d3353dd96711595c06326ac0195d1b
https://github.com/tgehr/dmd/commit/a0f59f93ab3727c93585dc658444860926a4b2c6

> but yes, not adding new types.

That's what I thought, so the tuple DIP is based on lowering to structs.

What's the path forward to making this work?

```d
double foo(int x,string y);

writeln([(1,"2"),(1,"3"),(3,"4")].map!foo);
```

My suggestion was proposal 2 here:
https://github.com/tgehr/DIPs/blob/tuple-syntax/DIPs/DIP1xxx-tg.md

Proof-of-concept implementation here:
https://github.com/tgehr/dmd/commit/bdb40fa96c471a7ace84596511a27ba3e803214f
https://github.com/tgehr/dmd/commit/dad942117d85683e6234ef312c6d59be82f0c3a2

Note that Phobos tuples are implemented using an `alias this` to a built-in "tuple" of members:
https://github.com/dlang/phobos/blob/master/std/typecons.d#L636-L655
January 04, 2022
On 1/3/2022 7:09 PM, Timon Gehr wrote:
> My DIP draft extends "alias this" to allow this (which should work anyway):
> 
> alias Seq(T...)=T;
> struct S{
>      byte b;
>      int c;
>      alias this=Seq!(b,c);
> }
> 
> void func(byte,int);
> 
> func(S());

I confess, this makes me uneasy. `alias this` produced a lot of unintended consequences. I'm gunshy of extending it. I'd prefer:

    func(S().tupleof);


> It does have some significant drawbacks, e.g. `foo(int,int)` and `foo((int,int))` would have a different ABI and the second overload can't be called as `foo(1,2);`...

I tried to actively avoid that :-)

> To be very clear, I want this:
> 
> [(1,2),(3,4)].map!((a,b)=>a+b).each!writeln;
> 
> An this is generally what people mean when they talk about "tuples".

I understand. It looks like a worthy goal.