January 14, 2018
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.

January 14, 2018
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.
January 14, 2018
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.
January 14, 2018
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).)
January 14, 2018
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).)
January 14, 2018
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.)
January 14, 2018
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.
January 15, 2018
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 :-)
January 15, 2018
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.
January 16, 2018
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);
}