www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - PackedAliasSeq?

reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
After coding https://github.com/dlang/phobos/pull/6192 with AliasSeq, 
the experience has been quite pleasurable. However, in places the 
AliasSeq tends to expand too eagerly, leading to a need to "keep it 
together" e.g. when you need to pass two of those to a template.

I worked around the issue by nesting templates like this:

template Merge(T...)
{
     template With(U...)
     {
         static if (T.length == 0)
             alias With = U;
         else static if (U.length == 0)
             alias With = T;
         else static if (T[0] < U[0]
                  || T[0] == U[0] && T[1].stringof <= U[1].stringof)
             alias With =
                 AliasSeq!(T[0], T[1], Merge!(T[2 .. $]).With!U);
        else
             alias With =
                 AliasSeq!(U[0], U[1], Merge!T.With!(U[2 .. $]));
     }
}

So instead of the unworkable Merge!(AliasSeq!(...), AliasSeq!(...)), one 
would write Merge!(AliasSeq!(...)).With!(AliasSeq!(...)).

The problem remains for other use cases, so I was thinking of adding to 
std.meta this simple artifact:

template PackedAliasSeq!(T...)
{
     alias expand = AliasSeq!T;
}

That way, everything stays together and can be expanded on demand.


Andrei
Feb 22 2018
next sibling parent Seb <seb wilzba.ch> writes:
On Thursday, 22 February 2018 at 19:26:54 UTC, Andrei 
Alexandrescu wrote:
 After coding https://github.com/dlang/phobos/pull/6192 with 
 AliasSeq, the experience has been quite pleasurable. However, 
 in places the AliasSeq tends to expand too eagerly, leading to 
 a need to "keep it together" e.g. when you need to pass two of 
 those to a template.

 [...]
You could also extend the existing `Pack` template: https://github.com/dlang/phobos/blob/master/std/meta.d#L1704
Feb 22 2018
prev sibling next sibling parent reply deadalnix <deadalnix gmail.com> writes:
On Thursday, 22 February 2018 at 19:26:54 UTC, Andrei 
Alexandrescu wrote:
 After coding https://github.com/dlang/phobos/pull/6192 with 
 AliasSeq, the experience has been quite pleasurable. However, 
 in places the AliasSeq tends to expand too eagerly, leading to 
 a need to "keep it together" e.g. when you need to pass two of 
 those to a template.

 I worked around the issue by nesting templates like this:

 template Merge(T...)
 {
     template With(U...)
     {
         static if (T.length == 0)
             alias With = U;
         else static if (U.length == 0)
             alias With = T;
         else static if (T[0] < U[0]
                  || T[0] == U[0] && T[1].stringof <= 
 U[1].stringof)
             alias With =
                 AliasSeq!(T[0], T[1], Merge!(T[2 .. $]).With!U);
        else
             alias With =
                 AliasSeq!(U[0], U[1], Merge!T.With!(U[2 .. $]));
     }
 }

 So instead of the unworkable Merge!(AliasSeq!(...), 
 AliasSeq!(...)), one would write 
 Merge!(AliasSeq!(...)).With!(AliasSeq!(...)).

 The problem remains for other use cases, so I was thinking of 
 adding to std.meta this simple artifact:

 template PackedAliasSeq!(T...)
 {
     alias expand = AliasSeq!T;
 }

 That way, everything stays together and can be expanded on 
 demand.


 Andrei
Isn't a packed AliasSeq just a tuple ?
Feb 23 2018
parent Petar Kirov [ZombineDev] <petar.p.kirov gmail.com> writes:
On Saturday, 24 February 2018 at 06:14:52 UTC, deadalnix wrote:
 On Thursday, 22 February 2018 at 19:26:54 UTC, Andrei 
 Alexandrescu wrote:
 After coding https://github.com/dlang/phobos/pull/6192 with 
 AliasSeq, the experience has been quite pleasurable. However, 
 in places the AliasSeq tends to expand too eagerly, leading to 
 a need to "keep it together" e.g. when you need to pass two of 
 those to a template.

 I worked around the issue by nesting templates like this:

 template Merge(T...)
 {
     template With(U...)
     {
         static if (T.length == 0)
             alias With = U;
         else static if (U.length == 0)
             alias With = T;
         else static if (T[0] < U[0]
                  || T[0] == U[0] && T[1].stringof <= 
 U[1].stringof)
             alias With =
                 AliasSeq!(T[0], T[1], Merge!(T[2 .. 
 $]).With!U);
        else
             alias With =
                 AliasSeq!(U[0], U[1], Merge!T.With!(U[2 .. 
 $]));
     }
 }

 So instead of the unworkable Merge!(AliasSeq!(...), 
 AliasSeq!(...)), one would write 
 Merge!(AliasSeq!(...)).With!(AliasSeq!(...)).

 The problem remains for other use cases, so I was thinking of 
 adding to std.meta this simple artifact:

 template PackedAliasSeq!(T...)
 {
     alias expand = AliasSeq!T;
 }

 That way, everything stays together and can be expanded on 
 demand.


 Andrei
Isn't a packed AliasSeq just a tuple ?
It is not a tuple (in the `std.typecons.Tuple` sense) if it can contain values, types and other kinds of symbols. I think a more appropriate name would be AliasTuple - an AliasSeq that doesn't auto-expand.
Feb 24 2018
prev sibling next sibling parent John Colvin <john.loughran.colvin gmail.com> writes:
On Thursday, 22 February 2018 at 19:26:54 UTC, Andrei 
Alexandrescu wrote:
 After coding https://github.com/dlang/phobos/pull/6192 with 
 AliasSeq, the experience has been quite pleasurable. However, 
 in places the AliasSeq tends to expand too eagerly, leading to 
 a need to "keep it together" e.g. when you need to pass two of 
 those to a template.

 I worked around the issue by nesting templates like this:

 template Merge(T...)
 {
     template With(U...)
     {
         static if (T.length == 0)
             alias With = U;
         else static if (U.length == 0)
             alias With = T;
         else static if (T[0] < U[0]
                  || T[0] == U[0] && T[1].stringof <= 
 U[1].stringof)
             alias With =
                 AliasSeq!(T[0], T[1], Merge!(T[2 .. $]).With!U);
        else
             alias With =
                 AliasSeq!(U[0], U[1], Merge!T.With!(U[2 .. $]));
     }
 }

 So instead of the unworkable Merge!(AliasSeq!(...), 
 AliasSeq!(...)), one would write 
 Merge!(AliasSeq!(...)).With!(AliasSeq!(...)).

 The problem remains for other use cases, so I was thinking of 
 adding to std.meta this simple artifact:

 template PackedAliasSeq!(T...)
 {
     alias expand = AliasSeq!T;
 }

 That way, everything stays together and can be expanded on 
 demand.


 Andrei
Yes, I love this stuff, lots of possibilities. E.g. import std.traits : isInstanceOf; import std.meta : allSatisfy, AliasSeq, staticMap, Alias; template Pack(T ...) { alias expand = T; enum length = expand.length; } enum isPack(alias T) = isInstanceOf!(Pack, T); template Head(alias P) if (isPack!P) { alias Head = Alias!(P.expand[0]); } template Tail(alias P) if (isPack!P) { alias Tail = Pack!(P.expand[1 .. $]); } template staticZip(Seqs ...) if (Seqs.length >= 2 && allSatisfy!(isPack, Seqs)) { enum len = Seqs[0].length; static foreach (Seq; Seqs[1 .. $]) static assert(Seq.length == len, "All arguments to staticZip must have the same length"); static if (len == 0) alias staticZip = AliasSeq!(); else alias staticZip = AliasSeq!(Pack!(staticMap!(Head, Seqs)), staticZip!(staticMap!(Tail, Seqs))); }
Feb 24 2018
prev sibling parent Simen =?UTF-8?B?S2rDpnLDpXM=?= <simen.kjaras gmail.com> writes:
On Thursday, 22 February 2018 at 19:26:54 UTC, Andrei 
Alexandrescu wrote:
 template PackedAliasSeq!(T...)
 {
     alias expand = AliasSeq!T;
 }
I started playing around with this a few days ago, and came up with another interesting abstraction - NamedPack: alias foo = NamedPack!("Type", int, "name", "foo"); assert(is(foo.Type == int)); assert(foo.name == "foo"); assert(foo.equals!(NamedPack!("Type", int, "name", "foo"))); And for good measure, a helper to define your own 'compile-time structs', for want of a better word: alias Field = DefinePack!("Type", Type, "name", string, "offset", int); alias field1 = Field!(int, "a", 0); assert(is(field1.Type == int)); assert(field1.name == "a"); assert(field1.offset == 0); assert(field1.equals!(NamedPack!("Type", int, "name", "a", "offset", 0))); One benefit over regular structs being of course that these will never end up in the binary. The more structured nature of this construct over the simple Pack template makes it useful where information would otherwise be Implementation and some more documentation: https://gist.github.com/Biotronic/8a2664c050f01aed5e0c45950509022b -- Simen
Feb 26 2018