November 01, 2020
On 11/1/20 1:37 PM, Delt wrote:
> On Sunday, 1 November 2020 at 16:37:19 UTC, Andrei Alexandrescu wrote:
>> On 11/1/20 5:15 AM, claptrap wrote:
>>> On Saturday, 31 October 2020 at 23:09:31 UTC, Manu wrote:
>>>> On Sat, Oct 31, 2020 at 12:05 PM Paul Backus via Digitalmars-d < digitalmars-d@puremagic.com> wrote:
>>>> Is "Alias Sequence" present in spec language?
>>>> This really demonstrates how much D needs first-class tuples; this area of
>>>> the language is a shit-fight, and essentially just a weird abuse of
>>>> template argument lists mixed with `alias` and some implementation defined
>>>> behaviour, which happens to look and feel a lot like a tuple.
>>>
>>> tuples already exists in other languages, in math / set theory, it's already a fairly well established idea and it seems a bit weird for D to invent its own name for what's essentially the same thing.
>>
>> It isn't the same thing.
> 
> Essentially the same != the same

They are very different.

November 02, 2020
On Sun, Nov 1, 2020 at 8:50 PM Ola Fosheim Grøstad via Digitalmars-d < digitalmars-d@puremagic.com> wrote:

> On Sunday, 1 November 2020 at 10:15:44 UTC, claptrap wrote:
> > To me "alias sequence" is an implementers name, it's named for how it's implemented not for the actual concept.
>
> Yes, but tuples should have struct semantics, and structs hold values, not aliases.
>

Why? I don't agree with this at all. I actually expect tuples DON'T have
struct semantics.
The thing my DIP talks about are things that don't have struct semantics...
what is that called?

Anyway, this would all become moot if the ... operator was
> designed to work with all static length objects that provide index-access and .length.
>

Make a DIP then. I don't like that idea. It's problematic to know if you are dealing with a kind of thing that can be unrolled until much later in semantic when it should have already been done.

It's trivial to implement a static unroll: `MyList[iota!(MyList.length)]...`
Which can easily become: `alias StaticUnroll(T) = T[iota!(T.length)]...`
->   `StaticUnroll!T`


November 02, 2020
On Mon, Nov 2, 2020 at 12:41 AM claptrap via Digitalmars-d < digitalmars-d@puremagic.com> wrote:

> On Sunday, 1 November 2020 at 10:45:48 UTC, Ola Fosheim Grøstad wrote:
> > On Sunday, 1 November 2020 at 10:15:44 UTC, claptrap wrote:
> >> To me "alias sequence" is an implementers name, it's named for how it's implemented not for the actual concept.
> >
> > Yes, but tuples should have struct semantics, and structs hold values, not aliases.
>
> Why should they? Why cant a tuple hold aliases? That's essentially what AliasSeq is isnt it?
>
> I mean you shouldn't have to use arrays at run time and then entitylist at compile time, just because its holding something CT only. An array is an array.
>
> Maybe Im being naive or idealistic though.
>

That's 1st-class-types talk ;)
It would be great if D had first-class types. Stefan has ideas how to move
in that direction, but my feeling has been that leadership is generally
against it.


November 01, 2020
On Sunday, 1 November 2020 at 21:47:26 UTC, Manu wrote:
> Why? I don't agree with this at all. I actually expect tuples DON'T have struct semantics.

Well, it is a good thing if they behave as immutable structs as you then can get a more uniform language.

> The thing my DIP talks about are things that don't have struct semantics...
> what is that called?

I was wrong, in a way, as structs can have aliases as fields (I believe phobos Tuple does this?). Although it would be better if it was more akin to typeid so that they had a counterpart at runtime (so that a regular function can return all tuples), but that would require a language change.

But it would also make what Stephan try to do easier? His typefunctions would just be regular functions returning a type-identifer.

> Make a DIP then. I don't like that idea. It's problematic to know if you are dealing with a kind of thing that can be unrolled until much later in semantic when it should have already been done.

The semantic passes can determine when the operator should be evaluated.


November 02, 2020
On Mon, Nov 2, 2020 at 8:15 AM Ola Fosheim Grøstad via Digitalmars-d < digitalmars-d@puremagic.com> wrote:

> On Sunday, 1 November 2020 at 21:47:26 UTC, Manu wrote:
> > Why? I don't agree with this at all. I actually expect tuples DON'T have struct semantics.
>
> Well, it is a good thing if they behave as immutable structs as you then can get a more uniform language.
>

I think it is conceptually improper for a tuple to have a memory layout; especially considering tuples can hold elements that are types or aliases in addition to typed values.


> > The thing my DIP talks about are things that don't have struct
> > semantics...
> > what is that called?
>
> I was wrong, in a way, as structs can have aliases as fields (I believe phobos Tuple does this?). Although it would be better if it was more akin to typeid so that they had a counterpart at runtime (so that a regular function can return all tuples), but that would require a language change.
>
> But it would also make what Stephan try to do easier? His typefunctions would just be regular functions returning a type-identifer.
>

I think type functions are a great initiative, and I've talked with him
about that a lot.
I don't think this DIP competes with type functions. I also think type
functions will need a LOT of work to materialise.

> Make a DIP then. I don't like that idea. It's problematic to
> > know if you are dealing with a kind of thing that can be unrolled until much later in semantic when it should have already been done.
>
> The semantic passes can determine when the operator should be evaluated.
>

Under my DIP, the map is applied very early, pre-semantic. The resulting
tuple must compile in context and make semantic sense, and this is very
important such that it can be used in a wide variety of interesting
contexts.
It's also extremely complicated to know what the output of `...` applied to
an array-like thing should be? Is it a tuple? If you apply `...` to an
array or a range, and it becomes a tuple, that is probably going to reveal
serious semantic problems.

Imagine this:
  void fun(MyRange r) { ... }

  MyRange constantRange;
  fun(constantRange); // <-- function receives range as argument
  fun(expr(constantRange)...); // <-- the function call fails because the
range got turned into a tuple.


Or this:
  immutable int[] allTheThings = [ ... ];
  alias Selection = AliasSeq!(5, 1, 15);
  alias res = allTheThings[Selection]...; // <-- we have an array, and a
tuple both participating in the map; if `...` applied to array-like-things,
then this extremely important pattern would be impossible

If it attempts a parallel expansion as is specified in the DIP, then
immediately, the lengths do not match, but more importantly, the expression
doesn't even make functional sense anymore.
This DIP applies to tuples, specifically, and exclusively. You need to
design a completely different DIP if you think that's wrong.


November 02, 2020
On Monday, 2 November 2020 at 03:49:41 UTC, Manu wrote:
> On Mon, Nov 2, 2020 at 8:15 AM Ola Fosheim Grøstad via Digitalmars-d < digitalmars-d@puremagic.com> wrote:
>> Well, it is a good thing if they behave as immutable structs as you then can get a more uniform language.
>
> I think it is conceptually improper for a tuple to have a memory layout; especially considering tuples can hold elements that are types or aliases in addition to typed values.

D should reduce the number of types you have to account for in generic code.

> It's also extremely complicated to know what the output of `...` applied to
> an array-like thing should be? Is it a tuple? If you apply `...` to an
> array or a range, and it becomes a tuple, that is probably going to reveal
> serious semantic problems.

It should not be a tuple, it should be an extension of a comma list. Think splat operator.

The compiler only needs to know the length of the sequence in order to expand.

>   fun(constantRange); // <-- function receives range as argument
>   fun(expr(constantRange)...); // <-- the function call fails

I dont understand this example.

>
> Or this:
>   immutable int[] allTheThings = [ ... ];
>   alias Selection = AliasSeq!(5, 1, 15);
>   alias res = allTheThings[Selection]...; // <-- we have an array, and a
> tuple both participating in the map; if `...` applied to array-like-things,
> then this extremely important pattern would be impossible

I suggested explicit indexing, so not a problem.



November 02, 2020
On Mon, Nov 2, 2020 at 4:30 PM Ola Fosheim Grøstad via Digitalmars-d < digitalmars-d@puremagic.com> wrote:

> On Monday, 2 November 2020 at 03:49:41 UTC, Manu wrote:
> > On Mon, Nov 2, 2020 at 8:15 AM Ola Fosheim Grøstad via Digitalmars-d < digitalmars-d@puremagic.com> wrote:
> >> Well, it is a good thing if they behave as immutable structs as you then can get a more uniform language.
> >
> > I think it is conceptually improper for a tuple to have a memory layout; especially considering tuples can hold elements that are types or aliases in addition to typed values.
>
> D should reduce the number of types you have to account for in generic code.
>

I'm not sure what this means.

> It's also extremely complicated to know what the output of
> > `...` applied to
> > an array-like thing should be? Is it a tuple? If you apply
> > `...` to an
> > array or a range, and it becomes a tuple, that is probably
> > going to reveal
> > serious semantic problems.
>
> It should not be a tuple, it should be an extension of a comma list. Think splat operator.


My DIP is not like that.

The compiler only needs to know the length of the sequence in
> order to expand.
>
> >   fun(constantRange); // <-- function receives range as argument
> >   fun(expr(constantRange)...); // <-- the function call fails
>
> I dont understand this example.
>

The type is lost, so by applying a map expression to an array-like-thing, you can't use it in its original context anymore.

>
> > Or this:
> >   immutable int[] allTheThings = [ ... ];
> >   alias Selection = AliasSeq!(5, 1, 15);
> >   alias res = allTheThings[Selection]...; // <-- we have an
> > array, and a
> > tuple both participating in the map; if `...` applied to
> > array-like-things,
> > then this extremely important pattern would be impossible
>
> I suggested explicit indexing, so not a problem.
>

I don't understand this comment.


November 02, 2020
On Monday, 2 November 2020 at 09:45:48 UTC, Manu wrote:
> On Mon, Nov 2, 2020 at 4:30 PM Ola Fosheim Grøstad via Digitalmars-d < digitalmars-d@puremagic.com> wrote:
>> D should reduce the number of types you have to account for in generic code.
>>
>
> I'm not sure what this means.

Tuples should work with all generic code that is willing to take a struct as input.

>> I suggested explicit indexing, so not a problem.
>>
>
> I don't understand this comment.

Assume tuple t1 and t2

IN:
  f("hello", tuple(t1[_], t2),...]
OUT:
  f("hello", tuple(t1[0], t2),tuple(t1[1], t2), tuple(t1[2], t2)]


November 02, 2020
After reading much of the discussion here, a lot of it is about the terminology I think and not substance.

It's clear to me that the way the DIP works is:

something...

expands all tuples within "something" according to the DIP rules.

So what is something? Depends on where it is used. My understanding is that the *result* is a tuple/AliasSeq, but the *input* could be anything that *contains* a tuple. It could be a list of types, it could be a template instantiation, it could be an alias, it could be an argument list. I think the only place it can't be used is as a parameter list (as ... is already defined there).

The concept itself is great, and powerful (I played with the implementation a while back).

What I think this DIP is missing is a good name for the "something".

I still also would like to know when I need to enclose the something in parentheses.

In the DIP for example:

alias Values = AliasSeq!(1, 2, 3);
alias Types = AliasSeq!(int, short, float);
pragma(msg, cast(Types)Values...);

> cast(int)1, cast(short)2, cast(float)3

How far back does the ... apply? For example, a postfix ++ operator does not go back as far as this suggests:

cast(int)foo++; => cast(int)(foo++);

So it seems logical that the above evaluates like:

cast(Types)(Values...)

But your example suggests otherwise.

This is why I asked about operator precedence.

One further issue that still hasn't been addressed (maybe you are planning on addressing it, but just haven't commented on my feedback), what about nesting?

(something... + 5)...

What happens here?

-Steve
November 02, 2020
On Wednesday, 28 October 2020 at 10:57:37 UTC, Jacob Carlborg wrote:
> On Tuesday, 27 October 2020 at 10:54:07 UTC, Mike Parker wrote:
>> This is the discussion thread for the first round of Community Review of DIP 1037, "Add Unary Operator ...":
>>
>> https://github.com/dlang/DIPs/blob/ba81eec84ddf0aeeb2cb652743b292455ec8c62a/DIPs/DIP1037.md
>
> Is there a risk of causing some form of ambiguity with variadic functions?

No, because the DIP does not propose anything with types. In the DIP, it says "expression" everywhere; it's for use in expressions, not types. It doesn't forbid types to occur in the tuple for good reasons, simply because types can very well occur in expression contexts, but the result will always be an expression. If you want a drastic example how far reaching expression vs type context is: given a type T, T[] can mean: slice of T or T.opIndex. If T defines static opIndex, in an expression context, T[] will mean T.opIndex, and in a type context, it will mean slice of T (kinda obvious). Let Ts := (T1, T2); if you'd do (Ts[]).sizeof... --- because ... is only valid in an expression context --- it *must* lower to (T1.opIndex.sizeof, T2.opIndex.sizeof). By the grammar given in the DIP, the ... do not have anything to do with the type expression stuff.

The example given in the DIP with `cast(Types)Values...` might work by accident because types are also expressions. By the grammar provided, `cast(Types[])Values...` could never work as intended! The example

    alias staticMap(alias F, T...) = F!T...;

cannot work. By the grammar provided, F!T... must be an expression, not a "type expression", but alias requires a type context as its target. (I.e. alias x = 5; doesn't work; alias x = y + 1; doesn't work either because the right-hand sides aren't types.)

In the Feedback Thread, I commented that it would be great to have the proposed operator apply to type contexts as well [1]. Didn't get an answer, but do hope I get one eventually.

Problem is, as you started digging: For a class C (and classes only, not structs or anything else), the parameter definition C... is already defined [2, see "4. For class objects"]. For example,

    class C { this(int, string) { } }
    void foo(C...) { }
    void main() { foo(1, "abc"); }

compiles [3]. So if C is the last entry in a type-only AliasSeq that is used in a parameter list, notations clash. Currently valid [4] code like

    import std.meta : AliasSeq;
    class C { this(int, string) { } }
    alias Types = AliasSeq!(int, string, C);
    void foo(Types args...) { }
    void main() { foo(1, "abc", 2, "xyz"); }

would no longer compile, since `Types...` would be the literal same as using `Types` without dots.

[1] https://forum.dlang.org/post/fogbdhcdeukiucbxxxns@forum.dlang.org
[2] https://dlang.org/spec/function.html#typesafe_variadic_functions
[3] https://run.dlang.io/is/GmgAaG
[4] https://run.dlang.io/is/DeGZF7