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