September 25, 2012
deadalnix:

> The problem with tuple() isn't its syntax, but what you can or can't do with the resulting tuple.

See my first posts in this thread :-)

On the other hand it's handy to have a compact syntax for something you use often (http://en.wikipedia.org/wiki/Zipf%27s_law ).

Bye,
bearophile
September 25, 2012
On 2012-09-25 12:05, deadalnix wrote:

> It can get pretty confusing with , separated declarations :
>
> int a, b = 3;

I wouldn't complain if that became illegal.

-- 
/Jacob Carlborg
September 25, 2012
On 9/25/12 6:10 AM, deadalnix wrote:
> Le 24/09/2012 16:59, foobar a écrit :
>> I'm a bit confused about what is specifically proposed here:
>> - Is the suggestion to limit tuples to >1 elements? *This* I'm against
>> for practical as well as completeness reasons. Andrei already provided
>> one example, and another would be a proper unit type. e.g.
>> void foo(int a) {}
>> void bar (int b) { return foo(b); }
>> - Is the suggestion to allow implicit conversion between (T) and T?
>> This brings almost no benefit - (you save two keystrokes?) and adds a
>> special case to the language. The added complexity really does not
>> justify this.
>
> In fact, they don't need to unpack only for 1 element tuples, but this
> is the tricky case. Today, tuples auto unpack on function call for
> instance :
>
> auto t = tuple (1, 2);
> foo(t); // call foo(int, int)

Actually that's not the case. You need to write

foo(t.expand);

(and I think that's a good thing).


Andrei
September 25, 2012
Le 25/09/2012 13:42, Jacob Carlborg a écrit :
> On 2012-09-25 12:05, deadalnix wrote:
>
>> It can get pretty confusing with , separated declarations :
>>
>> int a, b = 3;
>
> I wouldn't complain if that became illegal.
>

Nor me (it was already confusing and confusable with comma expressions), but a hell lot of code rely on comma declarations.
September 25, 2012
Le 25/09/2012 15:38, Andrei Alexandrescu a écrit :
> On 9/25/12 6:10 AM, deadalnix wrote:
>> Le 24/09/2012 16:59, foobar a écrit :
>>> I'm a bit confused about what is specifically proposed here:
>>> - Is the suggestion to limit tuples to >1 elements? *This* I'm against
>>> for practical as well as completeness reasons. Andrei already provided
>>> one example, and another would be a proper unit type. e.g.
>>> void foo(int a) {}
>>> void bar (int b) { return foo(b); }
>>> - Is the suggestion to allow implicit conversion between (T) and T?
>>> This brings almost no benefit - (you save two keystrokes?) and adds a
>>> special case to the language. The added complexity really does not
>>> justify this.
>>
>> In fact, they don't need to unpack only for 1 element tuples, but this
>> is the tricky case. Today, tuples auto unpack on function call for
>> instance :
>>
>> auto t = tuple (1, 2);
>> foo(t); // call foo(int, int)
>
> Actually that's not the case. You need to write
>
> foo(t.expand);
>
> (and I think that's a good thing).
>
>
> Andrei

OK, my bad. It means that tuple(...) behave differently than T... defined tuples.

And both behave differently than Caml or Haskell's tuples.

isn't the time for some unification ? Preferably on how tuples work in other languages, except if limitations can be shown and better proposal are made (and not include that in D2.xxx).
September 25, 2012
On 9/25/12 10:05 AM, deadalnix wrote:
> OK, my bad. It means that tuple(...) behave differently than T...
> defined tuples.
>
> And both behave differently than Caml or Haskell's tuples.
>
> isn't the time for some unification ? Preferably on how tuples work in
> other languages, except if limitations can be shown and better proposal
> are made (and not include that in D2.xxx).

I'm not sure actually. The way I look at it, built-in tuples are quite low-level (types can't be spelled, automatic expansion and flattening, undecided first-class semantics) and should seldom be dealt with directly. The best use of built-in tuples is in the implementation of truly well-behaved, composable tuples.

Andrei
September 25, 2012
You've shown it's clearly incompatible with the current language and would break lots of code. What would it break if assignment required explicit tuple brackets?

(int a, b) = foo(); // A tuple assignment, 'a' and 'b' will be filled in order by the multiple return values of foo()

int foo() {
    return 1;
}

(int a, b) = foo(); // Also valid and only sets 'a'


int, int foo() {
    return 1, 2;
}

int a = foo(); // Also valid and 'a' takes the first tuple value

(int a, auto b) = foo(); // Evaluated left to right so 'a' will take the first argument of foo and b will auto to a type or tuple of what remains. It will error if there is nothing remaining for b. This would still allow the clean expression of stand-alone tuples and function arguments and return values.

int, string a = 1, "hello";
int, string foo(double, double a) {
   return cast(int) (d[0] * d[1]), "hello";
}

Doesn't the needs of bracketing to determine order operation, (stuff) more or less imply that implicit conversion between one member tuples and the type of that tuple member is a requirement? Or would the (stuff, ) syntax be better?
September 25, 2012
On 9/23/12, Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org> wrote:
> http://www.prowiki.org/wiki4d/wiki.cgi?LanguageDevel/DIPs/DIP19

Oh, I completely forgot to mention this little bug I've had due to the comma operator a few weeks ago:

import std.stdio;

int getInt(string op)
{
    if (op, "a")
        return 1;
    else
    if (op == "b")
        return 2;
    else
        return 3;
}

void main()
{
    string op1 = "a";
    string op2 = "b";
    string op3 = "c";

    writeln(getInt(op1));
    writeln(getInt(op2));
    writeln(getInt(op3));
}

It was a result of a refactoring and the bug went unnoticed until I started getting weird results back. The if/else was much bigger and the comma was somewhere in the middle. So yeah, nuke it from orbit!
September 25, 2012
On 2012-09-25 15:08:25 +0000, Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org> said:

> On 9/25/12 10:05 AM, deadalnix wrote:
>> OK, my bad. It means that tuple(...) behave differently than T...
>> defined tuples.
>> 
>> And both behave differently than Caml or Haskell's tuples.
>> 
>> isn't the time for some unification ? Preferably on how tuples work in
>> other languages, except if limitations can be shown and better proposal
>> are made (and not include that in D2.xxx).
> 
> I'm not sure actually. The way I look at it, built-in tuples are quite low-level (types can't be spelled, automatic expansion and flattening, undecided first-class semantics) and should seldom be dealt with directly. The best use of built-in tuples is in the implementation of truly well-behaved, composable tuples.

The built-in tuple is also quite useful when defining templates.

In essence, we have two kinds of tuples: the built-in language tuple is the "unpacked" tuple while Phobos hosts the "packed" one. They each have their own use case and they can coexist peacefully. But the language itself needs to standardize on one or the other. Take this example (which is currently illegal because you can't return a built-in language tuple):

	T getThings(T...)(T t)
	{
		return t;
	}

In this situation, there is no question that the language tuple needs to work as an expanded tuple inside the parameter list of getTuple.

But now, what is the return type of makeTuple(1,2)? Obviously it's (int, int), but is (int, int) the same thing as T? Or is it a packed version of T? Well, it can't be a packed version of T because T is already the unpacked type. I mean that for a function that simply return its argument this should work:

	T t1;
	T t2 = getThings!(T)(t1);

If the language made T… a packed tuple instead, then we could use the packed tuple everywhere and unpack it where necessary, and something like this could be used to make a packed tuple:

	T getThings(T...)(T.expand t)
	{
		return T(t);
	}

	T t1;
	T t2 = getThings!(T)(t1.expand);

But we can't have it both ways, and the above would be a very drastic change to the language.

I'm of the opinion that if we want to add tuple returns to the language (which I'd certainly like), it'll have to be the same kind of tuple we currently have built-in in the language: the auto-expanding kind.

As we all know, this doesn't preclude anyone from building packed library tuples:

	Tuple!(T) getThings(T...)(T t)
	{
		return tuple(t);
	}

Although to make things less confusing, I think the built-in language tuple should give up its name. It could become a "sequence". Renaming the built-in one would certainly be less trouble, as code doesn't refer to it by its name, and you can pick a name that fits better with its auto-expanding behaviour.


-- 
Michel Fortin
michel.fortin@michelf.ca
http://michelf.ca/

September 25, 2012
On Tuesday, September 25, 2012 12:28:15 Michel Fortin wrote:
> Although to make things less confusing, I think the built-in language tuple should give up its name. It could become a "sequence". Renaming the built-in one would certainly be less trouble, as code doesn't refer to it by its name, and you can pick a name that fits better with its auto-expanding behaviour.

Not referred to by its name? It's refereed to as TypeTuple all over the place. It's arguably a bad name, but it would break a _lot_ of code to change it now.

- Jonathan M Davis