April 23, 2020 Re: I dun a DIP, possibly the best DIP ever | ||||
---|---|---|---|---|
| ||||
Posted in reply to Steven Schveighoffer | On 4/22/2020 6:18 AM, Steven Schveighoffer wrote:
> int double_int(int val) { return 2 * val; }
>
> T double_int(T val) { return val; }
>
> void double_ints(alias pred, T... args) {
> pred(double_int(args)...);
> }
This can be done with the array syntax proposal using UFCS:
void double_ints(alias pred, T... args) {
args.pred();
}
|
April 24, 2020 Re: I dun a DIP, possibly the best DIP ever | ||||
---|---|---|---|---|
| ||||
Posted in reply to Walter Bright | On Friday, 24 April 2020 at 04:22:47 UTC, Walter Bright wrote:
> On 4/22/2020 6:18 AM, Steven Schveighoffer wrote:
>> int double_int(int val) { return 2 * val; }
>>
>> T double_int(T val) { return val; }
>>
>> void double_ints(alias pred, T... args) {
>> pred(double_int(args)...);
>> }
>
> This can be done with the array syntax proposal using UFCS:
>
> void double_ints(alias pred, T... args) {
> args.pred();
> }
And how does this work for staticMap, which is essentially the same as double_ints above, but pred is a template?
template staticMap(alias Fn, T...) {
alias staticMap = args.// what do I put here to invoke array syntax?
}
--
Simen
|
April 24, 2020 Re: I dun a DIP, possibly the best DIP ever | ||||
---|---|---|---|---|
| ||||
Posted in reply to Manu | On Friday, 24 April 2020 at 00:16:52 UTC, Manu wrote:
> On a slightly unrelated note; there's a really interesting idea up-thread
> about making nested `...` not be expanded by the outer `...`
> For instance:
>
> template T(A, B...) { ... }
> T!(Tup1, Tup2...)...
I'm wondering if perhaps that's the wrong way around - AliasSeq already does that:
T!(Tup1, AliasSeq!Tup2)... // Should only expand Tup1
It might be that the more useful behavior is for ...-tuples to be expandable:
T!(AliasSeq!(int, char)..., AliasSeq!Tup2)... // Should expand to T!(int, Tup2), T!(char, Tup2)
--
Simen
|
April 24, 2020 Re: I dun a DIP, possibly the best DIP ever | ||||
---|---|---|---|---|
| ||||
Posted in reply to Walter Bright Attachments:
| On Fri, Apr 24, 2020 at 2:20 PM Walter Bright via Digitalmars-d < digitalmars-d@puremagic.com> wrote: > On 4/22/2020 5:04 AM, Manu wrote: > > [...] > > Ok, I've had a chance to think about it. It's a scathingly brilliant idea! > > But (there's always a but!) something stuck out at me. Consider arrays: > > > void test() > { > auto a = [1, 2, 3]; > int[3] b = a[]*a[]; // b[0] = a[0]*a[0]; b[1] = a[1]*a[1]; b[2] = > a[2]*a[2]; > int[3] c = a[]*2; // c[0] = a[0]*2; c[1] = a[1]*2; c[2] = a[2]*2; > } > > These look familiar! D tuples already use array syntax - they can be > indexed and > sliced. Instead of the ... syntax, just use array syntax! > > The examples from the DIP: > > ===================================== > --- DIP > (Tup*10)... --> ( Tup[0]*10, Tup[1]*10, ... , Tup[$-1]*10 ) > > --- Array syntax > Tup*10 > > ==================================== > --- DIP > alias Tup = AliasSeq!(1, 2, 3); > int[] myArr; > assert([ myArr[Tup + 1]... ] == [ myArr[Tup[0] + 1], myArr[Tup[1] + 1], > myArr[Tup[2] + 1] ]); > > --- Array > alias Tup = AliasSeq!(1, 2, 3); > int[] myArr; > assert([ myArr[Tup + 1] ] == [ myArr[Tup[0] + 1], myArr[Tup[1] + 1], > myArr[Tup[2] + 1] ]); > > =================================== > ---DIP > alias Values = AliasSeq!(1, 2, 3); > alias Types = AliasSeq!(int, short, float); > pragma(msg, cast(Types)Values...); > > ---Array > alias Values = AliasSeq!(1, 2, 3); > alias Types = AliasSeq!(int, short, float); > pragma(msg, cast(Types)Values); > > ================================= > ---DIP > alias OnlyTwo = AliasSeq!(10, 20); > pragma(msg, (Values + OnlyTwo)...); > > ---Array > alias OnlyTwo = AliasSeq!(10, 20); > pragma(msg, Values + OnlyTwo); > > > The idea is simply if we have: > > t op c > > where t is a tuple and c is not, the result is: > > tuple(t[0] op c, t[1] op c, ..., t[length - 1] op c) > > For: > > t1 op t2 > > the result is: > > tuple(t1[0] op t2[0], t1[1] op t2[1], ..., t1[length - 1] op t2[length > - 1]) > > The AST doesn't have to be walked to make this work, just do it as part of > the > usual bottom-up semantic processing. > I thought about this, but this reaches much further than `a op b `. When I considered your approach, it appeared to add a lot of edges and limits on the structure of the expressions, particularly where it interacts with var-args or variadic templates. The advantage is: > > 1. no new grammar > Fortunately, the grammar is trivial. > 2. no new operator precedence rules > 3. turn expressions that are currently errors into doing the obvious thing > This is compelling, but I couldn't think how it can work from end to end. Why does C++ use ... rather than array syntax? Because C++ doesn't have > arrays! > Another reason I introduce `...` is for static fold. The follow-up to this DIP would make this expression work: `Tup + ...` -> `Tup[0] + Tup[1] + ... + Tup[$-1]` For instance, up-thread it was noted that a static-fold algorithm may implement a find-type-in-tuple; it would look like this: `is(MyType == Types) || ...` <- evaluate `true` if MyType is present in Types with no template instantiation junk. So, the `...` is deliberately intended to being additional value. Can you show how your suggestion applies to some more complex cases (not yet noted in the DIP). // controlled expansion: alias Tup = AliasSeq!(0, 1, 2); alias Tup2 = AliasSeq!(3, 4, 5); [ Tup, Tup2... ]... -> [ 0, 3, 4, 5 ], [ 1, 3, 4, 5 ], [ 2, 3, 4, 5 ] // template instantiations alias TTup = AliasSeq!(int, float, char); MyTemplate!(Tup, TTup.sizeof...)... -> MyTemplate!(0, 4, 4, 1), MyTemplate!(1, 4, 4, 1), MyTemplate!(2, 4, 4, 1) // replace staticMap alias staticMap(alias F, T...) = F!T...; // more controlled expansion, with template arg lists AliasSeq!(10, Tup, 20)... -> ( 10, 0, 20, 10, 1, 20, 10, 2, 20 ) AliasSeq!(10, Tup..., 20) -> ( 10, 0, 1, 2, 20 ) // static fold (outside the scope of this DIP, but it's next in line) `Tup + ...` -> `Tup[0] + Tup[1] + ... + Tup[$-1]` // static find `is(MyType == Types) || ...` That said, with respect to these fold expressions, it would be ideal if they applied to arrays equally as I propose to tuples. |
April 24, 2020 Re: I dun a DIP, possibly the best DIP ever | ||||
---|---|---|---|---|
| ||||
Attachments:
| On Fri, Apr 24, 2020 at 3:51 PM Manu <turkeyman@gmail.com> wrote:
> On Fri, Apr 24, 2020 at 2:20 PM Walter Bright via Digitalmars-d < digitalmars-d@puremagic.com> wrote:
>
>> On 4/22/2020 5:04 AM, Manu wrote:
>> > [...]
>>
>> Ok, I've had a chance to think about it. It's a scathingly brilliant idea!
>>
>> But (there's always a but!) something stuck out at me. Consider arrays:
>>
>>
>> void test()
>> {
>> auto a = [1, 2, 3];
>> int[3] b = a[]*a[]; // b[0] = a[0]*a[0]; b[1] = a[1]*a[1]; b[2] =
>> a[2]*a[2];
>> int[3] c = a[]*2; // c[0] = a[0]*2; c[1] = a[1]*2; c[2] = a[2]*2;
>> }
>>
>> These look familiar! D tuples already use array syntax - they can be
>> indexed and
>> sliced. Instead of the ... syntax, just use array syntax!
>>
>> The examples from the DIP:
>>
>> =====================================
>> --- DIP
>> (Tup*10)... --> ( Tup[0]*10, Tup[1]*10, ... , Tup[$-1]*10 )
>>
>> --- Array syntax
>> Tup*10
>>
>> ====================================
>> --- DIP
>> alias Tup = AliasSeq!(1, 2, 3);
>> int[] myArr;
>> assert([ myArr[Tup + 1]... ] == [ myArr[Tup[0] + 1], myArr[Tup[1] + 1],
>> myArr[Tup[2] + 1] ]);
>>
>> --- Array
>> alias Tup = AliasSeq!(1, 2, 3);
>> int[] myArr;
>> assert([ myArr[Tup + 1] ] == [ myArr[Tup[0] + 1], myArr[Tup[1] + 1],
>> myArr[Tup[2] + 1] ]);
>>
>> ===================================
>> ---DIP
>> alias Values = AliasSeq!(1, 2, 3);
>> alias Types = AliasSeq!(int, short, float);
>> pragma(msg, cast(Types)Values...);
>>
>> ---Array
>> alias Values = AliasSeq!(1, 2, 3);
>> alias Types = AliasSeq!(int, short, float);
>> pragma(msg, cast(Types)Values);
>>
>> =================================
>> ---DIP
>> alias OnlyTwo = AliasSeq!(10, 20);
>> pragma(msg, (Values + OnlyTwo)...);
>>
>> ---Array
>> alias OnlyTwo = AliasSeq!(10, 20);
>> pragma(msg, Values + OnlyTwo);
>>
>>
>> The idea is simply if we have:
>>
>> t op c
>>
>> where t is a tuple and c is not, the result is:
>>
>> tuple(t[0] op c, t[1] op c, ..., t[length - 1] op c)
>>
>> For:
>>
>> t1 op t2
>>
>> the result is:
>>
>> tuple(t1[0] op t2[0], t1[1] op t2[1], ..., t1[length - 1] op
>> t2[length - 1])
>>
>> The AST doesn't have to be walked to make this work, just do it as part
>> of the
>> usual bottom-up semantic processing.
>>
>
> I thought about this, but this reaches much further than `a op b `.
> When I considered your approach, it appeared to add a lot of edges and
> limits on the structure of the expressions, particularly where it interacts
> with var-args or variadic templates.
>
> The advantage is:
>>
>> 1. no new grammar
>>
>
> Fortunately, the grammar is trivial.
>
>
>> 2. no new operator precedence rules
>> 3. turn expressions that are currently errors into doing the obvious thing
>>
>
> This is compelling, but I couldn't think how it can work from end to end.
>
> Why does C++ use ... rather than array syntax? Because C++ doesn't have
>> arrays!
>>
>
> Another reason I introduce `...` is for static fold.
> The follow-up to this DIP would make this expression work:
>
> `Tup + ...` -> `Tup[0] + Tup[1] + ... + Tup[$-1]`
>
> For instance, up-thread it was noted that a static-fold algorithm may
> implement a find-type-in-tuple; it would look like this:
> `is(MyType == Types) || ...` <- evaluate `true` if MyType is present in
> Types with no template instantiation junk.
>
> So, the `...` is deliberately intended to being additional value.
>
>
> Can you show how your suggestion applies to some more complex cases (not
> yet noted in the DIP).
>
> // controlled expansion:
> alias Tup = AliasSeq!(0, 1, 2);
> alias Tup2 = AliasSeq!(3, 4, 5);
> [ Tup, Tup2... ]... -> [ 0, 3, 4, 5 ], [ 1, 3, 4, 5 ], [ 2, 3, 4, 5 ]
>
> // template instantiations
> alias TTup = AliasSeq!(int, float, char);
> MyTemplate!(Tup, TTup.sizeof...)... -> MyTemplate!(0, 4, 4, 1),
> MyTemplate!(1, 4, 4, 1), MyTemplate!(2, 4, 4, 1)
>
> // replace staticMap
> alias staticMap(alias F, T...) = F!T...;
>
> // more controlled expansion, with template arg lists
> AliasSeq!(10, Tup, 20)... -> ( 10, 0, 20, 10, 1, 20, 10, 2, 20 )
> AliasSeq!(10, Tup..., 20) -> ( 10, 0, 1, 2, 20 )
>
> // static fold (outside the scope of this DIP, but it's next in line) `Tup + ...` -> `Tup[0] + Tup[1] + ... + Tup[$-1]`
>
> // static find
> `is(MyType == Types) || ...`
>
> That said, with respect to these fold expressions, it would be ideal if they applied to arrays equally as I propose to tuples.
>
I guess this is the key case you need to solve for:
template T(Args...) {}
T!(Tup) -> T!(0, 1, 2)
T!(Tup)... -> T!0, T!1, T!2
And the parallel expansion disambiguation is also critical:
T!(Tup, Tup2...)... -> T!(0, 3, 4, 5), T!(1, 3, 4, 5), T!(2, 3, 4, 5)
If you can solve those, the rest will probably follow.
|
April 23, 2020 Re: I dun a DIP, possibly the best DIP ever | ||||
---|---|---|---|---|
| ||||
Posted in reply to Manu | On 4/23/2020 10:51 PM, Manu wrote: > Another reason I introduce `...` is for static fold. > The follow-up to this DIP would make this expression work: > > `Tup + ...` -> `Tup[0] + Tup[1] + ... + Tup[$-1]` I expect static foreach can handle that. But we can dig a little deeper. D doesn't have a special syntax to sum the elements of an array, but it can use a library function to do it. The next observation is that to sum the elements of a tuple, all the tuple members need to be implicitly convertible to a single arithmetic type. There is a way to do that: [ Tup ] and now the tuple is converted to an array literal, which can be summed the same way array literals are currently summed. I.e. no need for extra syntax. > For instance, up-thread it was noted that a static-fold algorithm may implement a find-type-in-tuple; it would look like this: > `is(MyType == Types) || ...` <- evaluate `true` if MyType is present in Types with no template instantiation junk. > > So, the `...` is deliberately intended to being additional value. is(MyType in Types) could work. No need for ... > Can you show how your suggestion applies to some more complex cases (not yet noted in the DIP). > > // controlled expansion: > alias Tup = AliasSeq!(0, 1, 2); > alias Tup2 = AliasSeq!(3, 4, 5); > [ Tup, Tup2... ]... -> [ 0, 3, 4, 5 ], [ 1, 3, 4, 5 ], [ 2, 3, 4, 5 ] [ Tup ~ [Tup2] ] Though again, should be using arrays for this in the first place, not tuples. > // template instantiations > alias TTup = AliasSeq!(int, float, char); > MyTemplate!(Tup, TTup.sizeof...)... -> MyTemplate!(0, 4, 4, 1), MyTemplate!(1, 4, 4, 1), MyTemplate!(2, 4, 4, 1) Although we don't have UFCS for templates, this would be a point for that: Tup.MyTemplate!(TTup.sizeof) Otherwise it would suffer from the bottom-up semantic analysis problem I mention further on. > // replace staticMap > alias staticMap(alias F, T...) = F!T...; alias staticMap(alias F, T...) = F!T; > // more controlled expansion, with template arg lists > AliasSeq!(10, Tup, 20)... -> ( 10, 0, 20, 10, 1, 20, 10, 2, 20 ) What I don't like about this example is it can't be done with bottom-up semantics, which is what D normally does. It relies on some top-down modification for it, which is likely to cause all sorts of unexpected difficulties. See the UFCS example above, where Tup is moved outside of the argument list. > AliasSeq!(10, Tup..., 20) -> ( 10, 0, 1, 2, 20 ) AliasSeq!(10, Tup, 20) -> ( 10, 0, 1, 2, 20 ) > That said, with respect to these fold expressions, it would be ideal if they applied to arrays equally as I propose to tuples. There's a lot of merit to the idea of arrays and tuples using a common syntax, which is what I'm proposing. |
April 24, 2020 Re: I dun a DIP, possibly the best DIP ever | ||||
---|---|---|---|---|
| ||||
Posted in reply to Walter Bright | On Friday, 24 April 2020 at 06:32:16 UTC, Walter Bright wrote:
> [...]
>
>> // replace staticMap
>> alias staticMap(alias F, T...) = F!T...;
>
> alias staticMap(alias F, T...) = F!T;
>
> [...]
this would be a breaking change:
currently:
template F(T...)
{
}
alias staticMap(alias F, T...) = F!T;
pragma(msg, staticMap!(F, int, short).stringof);
-> F!(int, short)
but with that change suddenly:
pragma(msg, staticMap!(F, int, short).stringof);
-> SomeTuple!(F!int, F!short)
|
April 24, 2020 Re: I dun a DIP, possibly the best DIP ever | ||||
---|---|---|---|---|
| ||||
Posted in reply to WebFreak001 | On Friday, 24 April 2020 at 06:37:42 UTC, WebFreak001 wrote:
> On Friday, 24 April 2020 at 06:32:16 UTC, Walter Bright wrote:
>> [...]
>>
>>> // replace staticMap
>>> alias staticMap(alias F, T...) = F!T...;
>>
>> alias staticMap(alias F, T...) = F!T;
>>
>> [...]
>
> this would be a breaking change:
>
> currently:
> template F(T...)
> {
> }
>
> alias staticMap(alias F, T...) = F!T;
>
> pragma(msg, staticMap!(F, int, short).stringof);
> -> F!(int, short)
>
> but with that change suddenly:
> pragma(msg, staticMap!(F, int, short).stringof);
> -> SomeTuple!(F!int, F!short)
nope, compile error.
F does not have an eponymous member.
|
April 24, 2020 Re: I dun a DIP, possibly the best DIP ever | ||||
---|---|---|---|---|
| ||||
Posted in reply to Walter Bright Attachments:
| On Fri, Apr 24, 2020 at 4:35 PM Walter Bright via Digitalmars-d < digitalmars-d@puremagic.com> wrote: > On 4/23/2020 10:51 PM, Manu wrote: > > Another reason I introduce `...` is for static fold. > > The follow-up to this DIP would make this expression work: > > > > `Tup + ...` -> `Tup[0] + Tup[1] + ... + Tup[$-1]` > > I expect static foreach can handle that. But we can dig a little deeper. D > doesn't have a special syntax to sum the elements of an array, but it can > use a > library function to do it. The next observation is that to sum the > elements of a > tuple, all the tuple members need to be implicitly convertible to a single > arithmetic type. There is a way to do that: > > [ Tup ] > > and now the tuple is converted to an array literal, which can be summed > the same > way array literals are currently summed. I.e. no need for extra syntax. > > > > For instance, up-thread it was noted that a static-fold algorithm may > implement > > a find-type-in-tuple; it would look like this: > > `is(MyType == Types) || ...` <- evaluate `true` if MyType is present > in > > Types with no template instantiation junk. > > > > So, the `...` is deliberately intended to being additional value. > > is(MyType in Types) > > could work. No need for ... > You can imagine that the expressions could be far more elaborate than that. > Can you show how your suggestion applies to some more complex cases (not yet > > noted in the DIP). > > > > // controlled expansion: > > alias Tup = AliasSeq!(0, 1, 2); > > alias Tup2 = AliasSeq!(3, 4, 5); > > [ Tup, Tup2... ]... -> [ 0, 3, 4, 5 ], [ 1, 3, 4, 5 ], [ 2, 3, 4, 5 ] > > [ Tup ~ [Tup2] ] > > Though again, should be using arrays for this in the first place, not tuples. > > > > // template instantiations > > alias TTup = AliasSeq!(int, float, char); > > MyTemplate!(Tup, TTup.sizeof...)... -> MyTemplate!(0, 4, 4, 1), > MyTemplate!(1, > > 4, 4, 1), MyTemplate!(2, 4, 4, 1) > > Although we don't have UFCS for templates, this would be a point for that: > > Tup.MyTemplate!(TTup.sizeof) > > Otherwise it would suffer from the bottom-up semantic analysis problem I > mention > further on. > I think this only satisfies a narrow set of possibilities. There may be parallel expansion, and UFCS only handles one single UFCS argument, and also requires that it be the first argument. > // replace staticMap > > alias staticMap(alias F, T...) = F!T...; > > alias staticMap(alias F, T...) = F!T; And if `F` accepts variadic arguments? template F(Args...) > // more controlled expansion, with template arg lists > > AliasSeq!(10, Tup, 20)... -> ( 10, 0, 20, 10, 1, 20, 10, 2, 20 ) > > What I don't like about this example is it can't be done with bottom-up > semantics, which is what D normally does. It relies on some top-down > modification for it, which is likely to cause all sorts of unexpected > difficulties. See the UFCS example above, where Tup is moved outside of > the > argument list. > I'd like to know why you consider that troubling? We were able to implement this DIP in a relatively small and completely self-contained block of code. It's totally isolated, and easy to understand. > AliasSeq!(10, Tup..., 20) -> ( 10, 0, 1, 2, 20 ) > > AliasSeq!(10, Tup, 20) -> ( 10, 0, 1, 2, 20 ) > This is just normal D, but the first case (above) needs an expression. > That said, with respect to these fold expressions, it would be ideal if they > > applied to arrays equally as I propose to tuples. > > There's a lot of merit to the idea of arrays and tuples using a common > syntax, > which is what I'm proposing. > I agree. I'm wondering if it might be the case that `...` is still a useful operator to make expansion explicit and unambiguous, and my definition is expanded to apply to arrays in addition to tuples, which would maintain that uniformity. |
April 24, 2020 Re: I dun a DIP, possibly the best DIP ever | ||||
---|---|---|---|---|
| ||||
Posted in reply to Walter Bright Attachments:
| On Fri, Apr 24, 2020 at 4:35 PM Walter Bright via Digitalmars-d < digitalmars-d@puremagic.com> wrote:
> On 4/23/2020 10:51 PM, Manu wrote:
> > Another reason I introduce `...` is for static fold.
> > The follow-up to this DIP would make this expression work:
> >
> > `Tup + ...` -> `Tup[0] + Tup[1] + ... + Tup[$-1]`
>
> I expect static foreach can handle that. But we can dig a little deeper. D
> doesn't have a special syntax to sum the elements of an array, but it can
> use a
> library function to do it. The next observation is that to sum the
> elements of a
> tuple, all the tuple members need to be implicitly convertible to a single
> arithmetic type. There is a way to do that:
>
> [ Tup ]
>
No, it's not necessary that they are common types. It's actually the
opposite intent of the expression.
If they wanted what you say, they would write what you say today.
The point of tuple expansions as opposed to using an array is almost
certainly because you DO have mixed types.
If the BinOp is logical, anything that can coerce to true/false is
acceptable. If it's arithmetic, then operator overloads are probably part
of the equation.
|
Copyright © 1999-2021 by the D Language Foundation