Thoughts on possible tuple semantics

deadalnix deadalnix at gmail.com
Thu Aug 22 04:19:53 PDT 2013


So, I took some time to think about this. Let me propose 
something close, but different.

I'll try to define sequences more precisely and define some tools 
that allow to implement tuples in a nice way on top of it.

A sequence is an ordered set. You can have types, alias and 
values sequences. Values sequence can be runtime or compile time.

You can ask for sequences as parameter template using ... and 
using the regular template parameter syntax.

template(T) => template(T...)
template(alias T) => template(alias T...)
template(T U, T) => template(T U, T...)
template(T alias U) => template(T alias U..., T...)

Obviously, we want template(T...) to be a special for a 
transition period. T... being a subset of alias T..., we can 
start with a warning when the use it outside the subset.

It is a breaking change, but reduce the confusion by reusing the 
template parameter mechanism. Considering that most people here 
are very confused by type tuples, I highly doubt a lot of code is 
outside abusing this feature.

A type sequence can be used to define a value sequence :
auto foo(T...)(T args) { ... }

args is a value sequence. It isn't packed as a struct or 
anything, simply several values (here several function 
parameters) hidden behing one identifier. As a result, args do 
not have address or type.

typeof(args) returns T, which is a type sequence (not a type !)
typeid(args) is invalid.

Each member of args however have an address, a type and 
everything a function parameter have.

A sequence provide an access to its member via [index] and length 
to indicate its length. index need to be a compile time value, 
and length is a compile time value.

It is possible to use a sequence to define any ordered set of 
stuff (value sequence can be used for function call, type 
sequence to create multiple fields in a struct, etc . . .).

Right, most of what is described here is close from what we 
already have. Types sequence in a struct can be used to create 
tuples and IFTI can make it very handy.

Sequences can be built using the coma operator. int, float is a 
type sequence. args[0], args[1] is a value sequence. They can be 
returned from functions :

int, int foo() {
     return 3, 4;
}

int, int a = foo();

However, due to syntax conflict, int, int a = 3, 4; is not 
possible (it the value on the right is an assignment, it conflict 
with multiple declarations). () can be used to disambiguate : 
int, int a = (3, 4);

The missing piece is an auto dispatch function. I propose here a 
simple rewrite rule, as this is simple to implement and can be 
really effective.

auto (a, b) = foo();

is rewritten as

auto tmp = foo(); // Here tmp is a sequence of declaration of 
value. No need to create lvalues (especially is a complex copy is 
involved).
assert(tmp.length == 2); // Should be removed anyway for 
sequences.
auto a = tmp[0];
auto b = tmp[1];

This allow to make any user type unpackable. Or even arrays, 
slices, randomAccessRanges, etc . . .


More information about the Digitalmars-d mailing list