Thoughts on possible tuple semantics

Meta jared771 at gmail.com
Wed Aug 21 09:53:09 PDT 2013


On Wednesday, 21 August 2013 at 15:22:59 UTC, Dicebot wrote:
>     - Template argument sequence: may contain anything that is 
> legal template argument.

One thing I'd like to know. If we're at the point where we're 
discussing possible breaking changes to the language anyway, why 
is it so important that these tuples behave exactly like template 
argument lists? How important is it to be able to include both 
types AND values within the same tuple outside of variadic 
templates? I don't know if I've ever seen a use case for this.

>     - Value tuple or simply "tuple": may contain any values, 
> including run-time
>     values. Value storage location is not defined.

Are you implying that the address of a tuple cannot be taken?

> Template argument sequence that contains only types is called 
> "type sequence"
> and is considered a type on its own. Type of value tuple is a 
> type sequence.

I like this. Just to be clear, can you assign a type sequence to 
a variable or only alias it, like with regular types?

> Mixed template argument sequences are considered types too, but 
> special one. Those
> types can be aliased or passed to templates but can't be 
> instantiated.

What is the type of (42, string, dchar, false)? Is it (int, 
string, dchar, bool) (i.e., type sequence), or is it its own 
distinct type? Also, what operations can be done on a mixed 
tuple? Does this count as instantiation?:

void foo(T...)(T t) //Error?
{
     //...
}

> Each of these two entities has its own literal type. This is 
> required to avoid
> ambiguity between storing symbol as a type and taking its value 
> on run-time. Tuple
> always does the latter.

You're losing me. I sort of agree as to why, but I don't the idea 
of having two different tuples syntaces. That's part of why the 
situation is as it is in the first place. Yes, there needs to be 
a good way to make clear which type of tuple you're using, but I 
don't think two ways of making a tuple is a good thing.

> void foo(T...)(T args)

Looks like my earlier question was answered. Why is this not 
instantiation?

> {
>     static assert(is(T == ctseq(int, string)));
>     static assert(is(typeof(args) == T));
>     assert(args == tuple(1, "2"));
>     int a = 1;
>     string b = "2";
>     assert(args == tuple(a, b));
>     static assert(typeof(tuple(a, b)) == ctseq(int, string));
> }

Something else. How does tuple(1, "a") relate to ctuple(1, "a"), 
if at all? How does ctuple(int, string) relate to ctuple(1, "a")? 
Is there ever a case where typeof(tuple(value, value)) == 
ctuple(value, value), or ctuple(type, type) == ctuple(value, 
value)?

> // type semantics of type sequence
>
> ctseq(int, int) twoVars;
> twoVars[0] = 42;
> twovars[1] = 43;
> assert(twoVars == tuple(42, 43));
>
> ctseq(int, 42) twoVars; // compile-time error, can't 
> instantiate mixed template argument sequence
> assert(twoVars != ctseq(42, 42)); // NOT the same, breaking 
> change

Okay, one question answered.

> // compile-time vs run-time vs type semantics
>
> auto a1 = tuple(42, 42); // ok
> auto b1 = ctseq(42, 42); // error

Good, but second example will probably cause confusion.

> enum a2_1 = tuple(42, 42); // ok
> int a, b;
> enum a2_2 = tuple(a, b); // error

Makes perfect sense.

> enum b2 = ctseq(42, 42); // error, breaking change

Will probably cause confusion.

> alias a3 = tuple(42, 42); // error
> alias b3 = ctseq(42, 42); // ok

Great.

> One thing to consisder is .tupleof - should it result in actual 
> tuple or maintain
> current behavior? Former is probably more reasonable but it is 
> even more break

I think it should be consistent with how your hypothetical tuple 
semantics work in the other situations you described. That would 
be much less surprising than having only .tupleof auto-expand.

> struct S { int a, b, c; }
>
> foo(S.init.tupleof.expand); // huh

I don't see the "huh" here. Seems perfectly reasonable to me. Any 
code relying on this behaviour would break if members were added 
to S anyway (and code shouldn't rely on this, IMO).

> .expand should be probably defined as a simple syntax rewrite:
>     - tuple(a, b)" to "a, b" for literals
>     - "tupleVar" to "tupleVar[0], tupleVar[1]" for variables
>
> That also implies that packing / unpacking syntax, whatever it 
> can be,
> is completely unrelated to expansion - former can't be 
> expressed as a simple
> syntax rewrite, latter can't have special semantics tied to it 
> without creating
> even more meta-type to represent it.

I don't know what you mean here.

> ----- std.typetuple.TypeTuple / std.typecons.Tuple -----
>
> No need to keep them other than for backwards compatibility ;)

Wouldn't both break with the changes you described?


More information about the Digitalmars-d mailing list