August 21, 2013
On 8/21/13 8:22 AM, Dicebot wrote:
> Inspired by recent syntax thread I decided to write down by vision of
> how native language tuples should behave and how it may integrate into
> existing language state.

Awesome!

> Define two distinct built-in "tuples":
[snip]
> In further examples I will use imaginary syntax:
>      ctseq(int, string, 42) : template argument sequence
>      tuple("one", 2, three) : value tuple
>
>>>>>>
>
> // connections to existing template syntax
>
> void foo(T...)(T args)
> {
>      static assert(is(T == ctseq(int, string)));

There's going to be significant difficulty with this. This would be much easier:

      static assert(is(ctseq(T) == ctseq(int, string)));

Right now "T" as above has no type of its own, and ascribing a type to it would be a major change to which I think it's impossible to retrofit existing code without some breakages. If "T" is a type then "args" has a type and then we're back to asking ourselves whether writeln(args) passes one argument or more to writeln.

I do agree that we could take a different route if we designed the type system today, but we aren't. Current design is a legacy/liability.

>      static assert(is(typeof(args) == T));
>      assert(args == tuple(1, "2"));

So it seems the relationship between ctseq and tuple is that typeof(tuple(x, y. z)) is ctseq(typeof(x), typeof(y), typeof(z)). This leaves out of the discussion things like ctseq(1, "2") which contain compile-time values, not types. In that regard I'd prefer the two being entirely distinct.



Andrei
August 21, 2013
On Wednesday, 21 August 2013 at 19:18:52 UTC, Andrei Alexandrescu wrote:
>> void foo(T...)(T args)
>> {
>>     static assert(is(T == ctseq(int, string)));
>
> There's going to be significant difficulty with this. This would be much easier:
>
>       static assert(is(ctseq(T) == ctseq(int, string)));

It is not easier, it is returning to current issue I was trying to address - question "what is T and how it is related to existing type system".

> Right now "T" as above has no type of its own

Then why it can be aliased?

> If "T" is a type then "args" has a type and then we're back to asking ourselves whether writeln(args) passes one argument or more to writeln.

If we assume they auto-expansion is out, it is straightforward:
writeln(args) passes one argument, writeln(args.expand) - multiple.

> I do agree that we could take a different route if we designed the type system today, but we aren't. Current design is a legacy/liability.

Then, as I have already said, we can hardly do anything better than renaming TypeTuple and abandoning any hope to remove confusion. Well, maybe one can add some syntax sugar to make it more powerful, but built-ins will remain same weirdos.

And this is a time to step down for a moment and ask "is cumulative cost of documentation efforts and learning issues during all D lifespan worse than one hard by finite deprecation process?".

Current design is so hacky that we can't really do anything about it without breakage.

>>     static assert(is(typeof(args) == T));
>>     assert(args == tuple(1, "2"));
>
> So it seems the relationship between ctseq and tuple is that typeof(tuple(x, y. z)) is ctseq(typeof(x), typeof(y), typeof(z)). This leaves out of the discussion things like ctseq(1, "2") which contain compile-time values, not types. In that regard I'd prefer the two being entirely distinct.

They can't be distinct as both are accepted in one template argument list and this mandates that both must be able to be aliased. That makes them types. In my proposal ctseq(1, "2") also becomes a type, one that contains only meta-data and can't be instantiated.
August 22, 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 . . .
August 22, 2013
On Thursday, 22 August 2013 at 11:19:55 UTC, deadalnix wrote:
> A sequence is an ordered set. You can have types, alias and values sequences. Values sequence can be runtime or compile time.

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

1) You propose typeof to result "not a type" entity. Well, if it can be result of typeof, can be used to declare variables and can be aliased - what makes it different from a type?

2) is(typeof(tuple(42, 42)) == typeof(ctseq(42, 42))) == ? (assuming typeof(args) == T and you don't make distinction between runtime and compile-time value sequences.

Also you don't seem to cover mixed sequences which are essential to D templates.
August 22, 2013
On Thursday, 22 August 2013 at 12:50:06 UTC, Dicebot wrote:
> On Thursday, 22 August 2013 at 11:19:55 UTC, deadalnix wrote:
>> A sequence is an ordered set. You can have types, alias and values sequences. Values sequence can be runtime or compile time.
>
>> typeof(args) returns T, which is a type sequence (not a type !)
>> typeid(args) is invalid.
>
> 1) You propose typeof to result "not a type" entity. Well, if it can be result of typeof, can be used to declare variables and can be aliased - what makes it different from a type?
>

It is a sequence of types. It can be used to declare a sequence of variables.

> 2) is(typeof(tuple(42, 42)) == typeof(ctseq(42, 42))) == ? (assuming typeof(args) == T and you don't make distinction between runtime and compile-time value sequences.
>

In my proposal, tuple are a library construct. The proposal introduce the necessary tooling to implement them nicely.

is(typeof(42, 42) == (int, int));
is(typeof(tuple(42, 42)) == <a library defined struct>);

It could be defined as follow :

struct Tuple(T...) {
    T expand;
    alias expand this;
}

> Also you don't seem to cover mixed sequences which are essential to D templates.

Theses are alias sequences.
August 22, 2013
On Thursday, 22 August 2013 at 13:01:51 UTC, deadalnix wrote:
> It is a sequence of types. It can be used to declare a sequence of variables.

That implies defining "sequence of X" as special entity on official spec and update 'alias', 'typeof' and template docs to reference it as a special case.

> In my proposal, tuple are a library construct. The proposal introduce the necessary tooling to implement them nicely.
>
> is(typeof(42, 42) == (int, int));
> is(typeof(tuple(42, 42)) == <a library defined struct>);
>
> It could be defined as follow :
>
> struct Tuple(T...) {
>     T expand;
>     alias expand this;
> }

It is exactly what we have right now. So you think having two different types of expression/value tuples is fine?

>> Also you don't seem to cover mixed sequences which are essential to D templates.
>
> Theses are alias sequences.

As I have already said, it is no less confusing to classify as alias sequence something that is not limited to aliases.
August 22, 2013
On Thursday, 22 August 2013 at 14:03:13 UTC, Dicebot wrote:
> It is exactly what we have right now. So you think having two different types of expression/value tuples is fine?
>

One is a tuple, the other is a sequence. They are different beast and have different behavior.

The fact that it is similar to what we have now is on purpose, so we don't need to break a lot of code. Plus, with the proposed addition, it allow for nice library tuples.

>>> Also you don't seem to cover mixed sequences which are essential to D templates.
>>
>> Theses are alias sequences.
>
> As I have already said, it is no less confusing to classify as alias sequence something that is not limited to aliases.

It is what alias parameter for templates are. Simply keeping the terminology here.
August 22, 2013
On Thu, 22 Aug 2013 15:03:12 +0100, Dicebot <public@dicebot.lv> wrote:
>>> Also you don't seem to cover mixed sequences which are essential to D templates.
>>
>> Theses are alias sequences.
>
> As I have already said, it is no less confusing to classify as alias sequence something that is not limited to aliases.

I was thinking of it the other way round, as in .. It is not a sequence of aliases, but an alias for a sequence of .. expressions(?).  Perhaps calling it an "aliased sequence" makes that clearer?

R

-- 
Using Opera's revolutionary email client: http://www.opera.com/mail/
August 22, 2013
On Thursday, 22 August 2013 at 14:22:50 UTC, deadalnix wrote:
> One is a tuple, the other is a sequence. They are different beast and have different behavior.
>
> The fact that it is similar to what we have now is on purpose, so we don't need to break a lot of code. Plus, with the proposed addition, it allow for nice library tuples.

I am confused. You proposed tuple implementation is essentially the very same current std.typecons.Tuple is. So I can see only two differences between value sequence and tuple:

1) latter has address and ABI
2) former auto-expands

Anything else?

>>> Theses are alias sequences.
>>
>> As I have already said, it is no less confusing to classify as alias sequence something that is not limited to aliases.
>
> It is what alias parameter for templates are. Simply keeping the terminology here.

Wait, what? Alias parameters for templates have nothing to do with template argument lists (other than being one possible type of that list element). In other words, "T..." can contain more stuff than "alias T..." (imaginary syntax).

And, considering the fact that we already have two different alias semantics (for template alias parameters and normal aliases), it is a dangerous terminology to chose anyway.
August 22, 2013
On Thursday, 22 August 2013 at 14:27:01 UTC, Regan Heath wrote:
> On Thu, 22 Aug 2013 15:03:12 +0100, Dicebot <public@dicebot.lv> wrote:
>>>> Also you don't seem to cover mixed sequences which are essential to D templates.
>>>
>>> Theses are alias sequences.
>>
>> As I have already said, it is no less confusing to classify as alias sequence something that is not limited to aliases.
>
> I was thinking of it the other way round, as in .. It is not a sequence of aliases, but an alias for a sequence of .. expressions(?).  Perhaps calling it an "aliased sequence" makes that clearer?
>
> R

Well, it falls into the same issue "named after what you can do with it" vs "named after what it is". The very meaning of word "alias" suggests that calling something "alias for X" is just adding naming indirection on top of X ;)