Thoughts on possible tuple semantics

deadalnix deadalnix at gmail.com
Fri Aug 23 08:27:12 PDT 2013


On Thursday, 22 August 2013 at 19:48:36 UTC, H. S. Teoh wrote:
> Now *this* is something new, and worth talking about.
>
> Suppose we forget about the whole tuple fiasco, and forget that 
> there's
> such a thing as a tuple (or TypeTuple or whatever else there is 
> that's
> confusing everybody).  Just with this syntax alone, we can 
> solve all
> kinds of problems:
>
> - If f is a function that returns some kind of array, we can 
> have
>   automatic unpacking of arrays:
>
> 	int[] func() { return [1,2,3]; }
>
> 	void main() {
> 		auto (x, y, z) = func();
> 		// Equivalent to:
> 		// auto tmp = func();
> 		// x = tmp[0];
> 		// y = tmp[1];
> 		// z = tmp[2];
> 	}
>
> - We can automatically unpack regex matches:
>
> 	import std.regex;
> 	auto (x, y, z) = 
> inputString.match(`(\d+)\s+(\w+)\s+(\S+)`).captures;
> 	// x = string matched by (\d+)
> 	// y = string matched by (\w+)
> 	// z = string matched by (\S+)
>
> - Like you said, any indexable range can be supported by this 
> syntax. In
>   fact, I'd argue that you should be able to do this even with 
> just an
>   input range:
>
> 	auto (x, y, z) = makeInputRange();
>
>   should be translated into:
>
> 	auto tmp = makeInputRange();
> 	assert(!tmp.empty);
> 	auto x = tmp.front;
> 	tmp.popFront();
> 	assert(!tmp.empty);
> 	auto y = tmp.front;
> 	tmp.popFront();
> 	assert(!tmp.empty);
> 	auto z = tmp.front;
>
>   Since ranges are a major selling feature of D, I'd argue that
>   in-language support should be completely appropriate, and even
>   desirable. (In fact, foreach already understands what a range 
> is, so
>   why not extend it here as well.)
>

Yes that is the intended effect.

>
> You said that the missing piece was an auto dispatch function. 
> Well, I
> think if we add yet another piece to it, this could become a 
> killer
> feature in D, even regardless of what happens with the whole 
> tuples
> issue:
>
> The above is all nice and good, except that you can't pass a
> tuple/array/range return from a function into a poly-adic 
> function's
> arguments. That is to say:
>
> 	int[] func1() { return [1,2,3]; }
> 	void func2(int x, int y, int z) { ... }
>
> 	// Currently this line doesn't compile:
> 	func2(func1());
>
> I used int[] for illustration purposes only; it can also be, 
> say, an
> input range of ints:
>
> 	T func1() { ... }
> 	assert(isInputRange!T && is(ElementType!T == int));
>
> 	void func2(int x, int y, int z) { ... }
>
> 	func2(func1());
> 	// ^^^ this will be rewritten into:
> 	// auto tmp = func1();
> 	// auto arg1 = tmp.front;
> 	// tmp.popFront();
> 	// auto arg2 = tmp.front;
> 	// tmp.popFront();
> 	// auto arg3 = tmp.front;
> 	// func2(arg1, arg2, arg3);
>
> Of course, if T is an array, then it will be rewritten into
> func2(tmp[0], tmp[1], tmp[2]); same goes if T is a Tuple, etc.. 
> Anything
> indexable with array notation should undergo this rewriting. So 
> you
> could write:
>
> 	Tuple!(int,string,bool) func1() {
> 		return tuple(1, "a", true);
> 	}
>
> 	void func2(int x, string y, bool z) { ... }
>
> 	func2(func1());
> 	// ^^^^ this gets rewritten into:
> 	// auto tmp = func1();
> 	// func2(tmp[0], tmp[1], tmp[2]);
>
> My point is that this auto-dispatch / auto-repack is not 
> limited to
> tuples alone. It can be made to work in a nice way to anything 
> that has
> array indexing notation or a range interface.
>
> This would solve the problem of multiple return values, for 
> example. You
> could have a div() function that returns a quotient and 
> remainder:
>
> 	auto div(int x, int y) {
> 		...
> 		return [q, r];
> 		// Or, (q, r), or a 2-element input range
> 	}
>
> 	auto (x, y) = div(13, 7);
>
>
> T

I'd like to see that being allowed explicitly, not implicitly as 
you propose.

foo(int, int, int) must be different than foo(int[3]) . If not, 
the TypeTuple unpacking mess is taken to yet another level.

The good news is that this is implementable with the proposal :

int, int, int dispatch(int[3] args) {
     return args[0], args[1], args[2];
}

foo(dispatch(arr));

To sum up, the only major change my proposal got it the ability 
to return values sequences. That plus some syntaxic sugar provide 
everything we need.

I'm thinking about it for month now and it only poped recently. 
I'm now convinced that this is the way forward :
  - If ABI allow multiple return values, we can take advantage of 
it.
  - We can have clean tuples.
  - We give more expressiveness to user defined types.


More information about the Digitalmars-d mailing list