Jump to page: 1 2
Thread overview
[phobos] More tuple algorithms with std.meta
Sep 27, 2010
Shin Fujishiro
Sep 27, 2010
Robert Jacques
Sep 28, 2010
Shin Fujishiro
Sep 28, 2010
Robert Jacques
Sep 28, 2010
Philippe Sigaud
Sep 27, 2010
Philippe Sigaud
Sep 28, 2010
Shin Fujishiro
Sep 28, 2010
Philippe Sigaud
Oct 03, 2010
Philippe Sigaud
Oct 04, 2010
Shin Fujishiro
Oct 10, 2010
Philippe Sigaud
Oct 11, 2010
Shin Fujishiro
Oct 11, 2010
Philippe Sigaud
September 27, 2010
I'm willing to add more tuple algorithms to phobos for easing metaprogramming in D.  Here's code and example:

  http://gist.github.com/598659

----------
alias staticSort!(
        q{ a.at!(0).sizeof < b.at!(0).sizeof },
        staticZip!( Wrap!(int, double, byte),
                    Wrap!("x", "y", "z")))
      A;
pragma(msg, A);
// tuple(Wrap!(byte,"z"),Wrap!(int,"x"),Wrap!(double,"y"))
----------

Built-in tuples have been able to store non-type compile-time entities. So, I propose we should rename the current TypeTuple to StaticTuple, and gather generic (non-type specific) tuple algorithms into a new module: std.meta.

Does it sound good?


Shin
September 27, 2010
On Mon, 27 Sep 2010 02:17:19 -0400, Shin Fujishiro <rsinfu at gmail.com> wrote:

> I'm willing to add more tuple algorithms to phobos for easing metaprogramming in D.  Here's code and example:
>
>   http://gist.github.com/598659
>
> ----------
> alias staticSort!(
>         q{ a.at!(0).sizeof < b.at!(0).sizeof },
>         staticZip!( Wrap!(int, double, byte),
>                     Wrap!("x", "y", "z")))
>       A;
> pragma(msg, A);
> // tuple(Wrap!(byte,"z"),Wrap!(int,"x"),Wrap!(double,"y"))
> ----------
>
> Built-in tuples have been able to store non-type compile-time entities. So, I propose we should rename the current TypeTuple to StaticTuple, and gather generic (non-type specific) tuple algorithms into a new module: std.meta.
>
> Does it sound good?
>
>
> Shin
> _______________________________________________
> phobos mailing list
> phobos at puremagic.com
> http://lists.puremagic.com/mailman/listinfo/phobos

The meta namespace has been proposed as a possible replacement for __traits, etc. i.e. meta.compiles() vs __traits(compiles, ). So a different module name might be appropriate.
September 27, 2010
On Mon, Sep 27, 2010 at 08:17, Shin Fujishiro <rsinfu at gmail.com> wrote:

> I'm willing to add more tuple algorithms to phobos for easing metaprogramming in D.  Here's code and example:
>
>  http://gist.github.com/598659
>
> ----------
> alias staticSort!(
>        q{ a.at!(0).sizeof < b.at!(0).sizeof },
>        staticZip!( Wrap!(int, double, byte),
>                    Wrap!("x", "y", "z")))
>      A;
> pragma(msg, A);
> // tuple(Wrap!(byte,"z"),Wrap!(int,"x"),Wrap!(double,"y"))
> ----------
>
> Built-in tuples have been able to store non-type compile-time entities. So, I propose we should rename the current TypeTuple to StaticTuple, and gather generic (non-type specific) tuple algorithms into a new module: std.meta.
>
> Does it sound good?
>
>
> Shin
>

I'm willing to review your code. I also feel Phobos should showcase D metaprogramming on types. At a minimum, filtering, reducing, scanning (reduce with history), rotating and inverting tuples should be there.

As for calling TypeTuple a StaticTuple, I prefer to keep TypeTuple. By
convergent evolution, I have lots of template that do similar things to your
and can confirm these are not just an intellectual exercise: as soon as you
transform functions for example, you need to transform their parameters
typetuple. The same for transforming a class/struct inner types, etc.
I also choose to call them staticStuff, but it's becoming a bit
cumbersome... Any idea to simplify the names would be welcome.

I decided to separate those acting on typetuple and those acting on
expression tuples / std.typecons.Tuple.
My code is here:

http://www.dsource.org/projects/dranges/browser/trunk/dranges/typetuple.d http://www.dsource.org/projects/dranges/browser/trunk/dranges/variadic.d http://www.dsource.org/projects/dranges/browser/trunk/dranges/tuple.d

If think most templates dealing with type tuples (or rather, template
arguments tuples) should go in std.typetuple.
Those acting on expression tuples could go in std.variadic.


Philippe
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.puremagic.com/pipermail/phobos/attachments/20100927/18ac3e82/attachment.html>
September 28, 2010
Philippe Sigaud <philippe.sigaud at gmail.com> wrote:
> I'm willing to review your code. I also feel Phobos should showcase D metaprogramming on types. At a minimum, filtering, reducing, scanning (reduce with history), rotating and inverting tuples should be there.

Thanks!  Please note: D metaprogramming is not only on types, but also on symbols and compile-time constants - possibly combined with mixins.

I mean, static tuple algorithms should be able to handle tuples composed of heterogeneous entities: types, symbols and/or constants.  It will allow us to write something like follows in a short, functional style:

  Struct!(int, "x", double, "y")
  http://gist.github.com/600535


> I decided to separate those acting on typetuple and those acting on
> expression tuples / std.typecons.Tuple.
> My code is here:
> 
> http://www.dsource.org/projects/dranges/browser/trunk/dranges/typetuple.d http://www.dsource.org/projects/dranges/browser/trunk/dranges/variadic.d http://www.dsource.org/projects/dranges/browser/trunk/dranges/tuple.d
> 
> If think most templates dealing with type tuples (or rather, template
> arguments tuples) should go in std.typetuple.
> Those acting on expression tuples could go in std.variadic.

I did know them. ;-)  I thought of proposing your templates if someone
was interested in this topic.  (dranges.templates is interesting, too.)

As for the separation of typetuple and variadic...  As I mentioned above, I think static tuple algorithms should be able to work with heterogeneous tuples.  Limiting algorithms only on types is not a choice for me.

But it does *not* mean I think the variadic is useless!  Note that I'm talking about compile-time operation on template tuple parameters; std.variadic algorithms would be definitely useful in run-time code. variadicMap is especially a gem!


Shin
September 28, 2010
"Robert Jacques" <sandford at jhu.edu> wrote:
> The meta namespace has been proposed as a possible replacement for __traits, etc. i.e. meta.compiles() vs __traits(compiles, ). So a different module name might be appropriate.

I'll consider.  BTW, will this really happen, or rather is it necessary? IIRC, the proposal was against the ugly syntax.  I think all the existing __traits except compiles could be wrapped with library templates with syntactic sanity and added flexibility.  For example:


template getMember(alias Scope, string member)
{
    alias Identity!(__traits(getMember, Scope, member)) getMember;
}

// This overload does partial application.  Useful for staticMap etc.
template getMember(alias Scope)
{
    template getMember(string member)
    {
        alias .getMember!(Scope, member) getMember;
    }
}


Shin
September 28, 2010
On Tue, 28 Sep 2010 06:10:56 -0400, Shin Fujishiro <rsinfu at gmail.com> wrote:

> "Robert Jacques" <sandford at jhu.edu> wrote:
>> The meta namespace has been proposed as a possible replacement for
>> __traits, etc. i.e. meta.compiles() vs __traits(compiles, ). So a
>> different module name might be appropriate.
>
> I'll consider.  BTW, will this really happen, or rather is it necessary? IIRC, the proposal was against the ugly syntax.  I think all the existing __traits except compiles could be wrapped with library templates with syntactic sanity and added flexibility.  For example:
>
>
> template getMember(alias Scope, string member)
> {
>     alias Identity!(__traits(getMember, Scope, member)) getMember;
> }
>
> // This overload does partial application.  Useful for staticMap etc.
> template getMember(alias Scope)
> {
>     template getMember(string member)
>     {
>         alias .getMember!(Scope, member) getMember;
>     }
> }
>
>
> Shin

I don't know if this is on the road map or not, I just remember a decently serious discussion about it. I do like your solution, although some __traits would require tuples of aliases and for aliases to support types in addition to expressions. Since we'd hopefully be able to do both some time in the future, no reason not to start a limited form of it now. Also, since things like getMember are fairly generic for the public namespace, they should probably be put into a holding struct (e.g. meta). This could also apply to your staticMap, staticReduce, etc. (i.e. meta.map and meta.reduce). This has the advantage of using with(meta){ } when large blocks of metaprogramming are written.
September 28, 2010
On Tue, Sep 28, 2010 at 16:52, Robert Jacques <sandford at jhu.edu> wrote:
>
> On Tue, 28 Sep 2010 06:10:56 -0400, Shin Fujishiro <rsinfu at gmail.com> wrote:
>
>> "Robert Jacques" <sandford at jhu.edu> wrote:
>>>
>>> The meta namespace has been proposed as a possible replacement for
>>> __traits, etc. i.e. meta.compiles() vs __traits(compiles, ). So a
>>> different module name might be appropriate.
>>
>> I'll consider. ?BTW, will this really happen, or rather is it necessary? IIRC, the proposal was against the ugly syntax. ?I think all the existing __traits except compiles could be wrapped with library templates with syntactic sanity and added flexibility. ?For example:
>>
>>
>> template getMember(alias Scope, string member)
>> {
>> ? ?alias Identity!(__traits(getMember, Scope, member)) getMember;
>> }
>>
>> // This overload does partial application. ?Useful for staticMap etc.
>> template getMember(alias Scope)
>> {
>> ? ?template getMember(string member)
>> ? ?{
>> ? ? ? ?alias .getMember!(Scope, member) getMember;
>> ? ?}
>> }

Looking at it, most traits seems wrappable in this way, except 'compiles'.

[meta]
> I don't know if this is on the road map or not, I just remember a decently serious discussion about it. I do like your solution, although some __traits would require tuples of aliases and for aliases to support types in addition to expressions. Since we'd hopefully be able to do both some time in the future, no reason not to start a limited form of it now. Also, since things like getMember are fairly generic for the public namespace, they should probably be put into a holding struct (e.g. meta). This could also apply to your staticMap, staticReduce, etc. (i.e. meta.map and meta.reduce). This has the advantage of using with(meta){ } when large blocks of metaprogramming are written.


And I find it easier on the eye to see meta.filter than staticFilter (even though I'm using the latter in my code).


Philippe



std.compiletime?
September 28, 2010
On Tue, Sep 28, 2010 at 09:50, Shin Fujishiro <rsinfu at gmail.com> wrote:
> Philippe Sigaud <philippe.sigaud at gmail.com> wrote:
>> I'm willing to review your code. I also feel Phobos should showcase D metaprogramming on types. At a minimum, filtering, reducing, scanning (reduce with history), rotating and inverting tuples should be there.
>
> Thanks! ?Please note: D metaprogramming is not only on types, but also on symbols and compile-time constants - possibly combined with mixins.

That's OK with me. What about I read and comment on your code before the end of the week? (Err, make that the very end of the week)

>
> I mean, static tuple algorithms should be able to handle tuples composed of heterogeneous entities: types, symbols and/or constants.

Agreed. Ok, any compile-time sorcery on template-y arguments tuples.

>?It will
> allow us to write something like follows in a short, functional style:
>
> ?Struct!(int, "x", double, "y")
> ?http://gist.github.com/600535

Nice!

(I'd have filtered TypeNames to get types in a tuple and names in another, instead of striding TypeNames. But I say that only because I'm jealous of what you've done :)  )


>?(dranges.templates is interesting, too.)

having templates acting on templates is fun :) It's easy to do, too: meta-meta-programming, something that would have blown my mind in C++ :)

>
> As for the separation of typetuple and variadic... ?As I mentioned above, I think static tuple algorithms should be able to work with heterogeneous tuples. ?Limiting algorithms only on types is not a choice for me.

OK. I indeed did them initially only as a way to generate types, when I was having troubles with auto.

>
> But it does *not* mean I think the variadic is useless! ?Note that I'm talking about compile-time operation on template tuple parameters; std.variadic algorithms would be definitely useful in run-time code.


Banco for a separation between 'acting on tuples at CT' on one hand and 'acting on tuples at runtime' on another.


> variadicMap is especially a gem!

Thanks. That's strange, D has wonderfully powerful metaprogramming
abilities, but no one seems to care. How many languages can offer a
statically checked mapping of a polymorphic function on a
heterogeneous list, in a few lines of code?
And it's not just an esoteric goal: you can transform structs.tupleof
or function arguments as you wish!


Philippe
September 28, 2010
On 9/28/10 13:27 PDT, Philippe Sigaud wrote:
> On Tue, Sep 28, 2010 at 09:50, Shin Fujishiro<rsinfu at gmail.com>  wrote:
>> Philippe Sigaud<philippe.sigaud at gmail.com>  wrote:
>> I mean, static tuple algorithms should be able to handle tuples composed
>> of heterogeneous entities: types, symbols and/or constants.
>
> Agreed. Ok, any compile-time sorcery on template-y arguments tuples.

I must say that a very healthy approach is to not be extravagant without solid use cases. There are lots of things that look cute and interesting in this style of programming, and getting carried away is probably the #1 risk.

>>   It will
>> allow us to write something like follows in a short, functional style:
>>
>>   Struct!(int, "x", double, "y")
>>   http://gist.github.com/600535
>
> Nice!

Isn't that as good as Tuple?

> Thanks. That's strange, D has wonderfully powerful metaprogramming
> abilities, but no one seems to care. How many languages can offer a
> statically checked mapping of a polymorphic function on a
> heterogeneous list, in a few lines of code?
> And it's not just an esoteric goal: you can transform structs.tupleof
> or function arguments as you wish!

It's fine if the traction is little in the beginning. There has been very little initial traction for some stuff I've done too. Some never gained traction, but some did. If it's good, people will notice.


Andrei
October 03, 2010
OK, Shin, I'm due a review of your code. Here it is:

As a general note, I find it quite elegant, even though I found your
constant use of a subdivide-and-recurse scheme a bit strange.
It makes for some clean implementations, but also complicates matters
in some cases. I'll indicate when I think a standard, linear
implementation might be more readable.

Also, maybe it'd be best if you introduced helper templates first. I believe Phobos does this.

Anyway...

l. 8: Why redefining TypeTuple as StaticTuple? I agree the name is a
bit of a misnomer,
but I'd prefer your module to use already defined templates if possible.

l. 21-40: staticMap : instead of testing for seq.length<2 and then
have a special case for == 0, I'd write
test for == 0
else test for == 1
else (the rest)

I grok Instantiate!template.With!arguments, but really in this case
and many other, you just use a subcase.
Why not do directly map!(seq[0])?

Also, mapping is inherently linear n my mind, so using a
dividing&recurse algorithm here seems strange.
The same for filtering.

l. 55: why seq and not seq[0]? Because you want the result to always be a tuple?

l.93 (staticReduce).Ideally, there should be a 2-args version that
takes seq[0] as a seed.

l. 117: bindFront OK. Good one!

l. 143: what is m? Is that the predicate's arity? That can be
determined, given a template's symbol.
So that could be done automatically here.

l. 156: I suggest: enum size_t index = 0;

l. 210: maybe you should test for pred being a binary template (arity == 2)

l. 302 (staticCountIf): another example of recursing being strange to my eye.
Cannot it just be staticFilter!(pred, seq).length?

l. 304-316: I suggest to reorganize the code with
* length == 0
* length == 1
* else

l. 352 (_staticReplace(tr...): what if tr.length is not 2? Why not
just do _staticReplace(from,to)?

l. 354-355: what's the usefulness of Identity in this case? Cannot just "alias tr[0] from;" work?

l. 377 (staticMost): it's a kind of fold, so it's implementable with
staticReduce. Maybe staticReduce!(selectWith!comp, seq)
with

template selectWith(comp)
{
	template selectWith(A,B)
	{
		static if (comp!(A,B) )
			alias A selectWith;
		else
			alias B selctWith;
	}
}

or something like that, anyway.

l. 384 & 388: why Identity?

l. 414 (merge sort on tuples at CT): Nice one!

l. 422 & 430, 432 & 437: Does the compiler know what template to instantiate for an empty tuple? I thought that was considered ambiguous?

l. 439-448: I suggest to invert B and A in the test. Mostly, you want
to do comp!(A[0],B[0]).
And then do the then branch with A, the else branch with B. Looks more
natural to me.

l. 453: No, no ditto.

l. 498 & 506, 508 & 513: No ambiguity for an empty tuple?

l. 534: No, no ditto.

l. 565: <2 might be better, to be consistent.

l. 593: What's the difference with staticUniq?

l. 595 here also, choose <=1 or <2, but stick with it for the entire module.

l. 636-655: You know, I'd suggest a linear approach here. It'd be more
readable and probaby reduce the
number of lines.

l. 664: why do you have staticStride return 1-element tuples instead of directly the elements?

l. 679-681: for me, another example of the dividing/recursing algo
complicating things greatly.
You even have to introduce a helper template _strideMid.
Why not just:

alias StaticTuple!(seq[0], staticStride!(n, seq[n .. $])) staticStride;

l. 699: you should test for .Expand being legal. Or maybe introduce a
isTupleOfTuples template.
Maybe implement staticTransverse with staticMap.

As a general comment on the tuples-of-tuples code: there should be a way to segment a tuple into a tuple of n-elements tuples.

l. 732: staticZip: good idea! I never had the energy to code this. staticZipWith would be cool.

l. 763: staticPermutations: do you have a use case in mind? l. 765: (5 is the limit). Really? 120 5-tuplets is the limit?

l. 781 & 787: I believe metaArray is not defined in the module.

l. 879 / 884: same ambiguity question. Nice code, btw.

l. 928-929: Once more, I don't find subdividing like this the most
obvious way to code iota
Having to introduce _iotaMid feels strange.

l. 1000. Wrap is good, but I'd prefer not to introduce another
Tuple-like template.
I'd suggest using std.typecons.Tuple and extend it when possible. When
that's not possible
(as Tuple is a type and not a 'pure' template), use a free template.
For example template insertFront(A, Tuple)

l. 1113: Very clever, forcing the compiler to generates the two inner
templates to compare the arguments.
That's for being able to test aliases too, right?

l. 1271 & 1280 (templateAnd, templateOr): These are quite useful, good
idea to add them.
I have the basis of a 'type pattern' module, to look for patterns in
tuples, like for regexes. Maybe that could interest someone.
alias Either!(int, OneOrMore!double, And!(string, double)) Pattern; //
for example

l. 1295 (templateCompose): Oh yes.

Good job!

Btw, I tested Robert's suggestion to put things in a struct called meta, and it worked:

module metaprogramming;

struct meta
{
	template map { ... }
}

*-----------*

module foo;
import metaprogramming;

void main()
{
	alias meta.map!(isIntegral, int, double, string, byte) Result;
	writeln([Result]);
}

I find meta.* much cleaner than static* and such.


Executive Summary:
- Very nice code, very clever, lots of interesting things in there.
Maybe sometimes too clever for a standard library, that should *also*
be
a way to learn the language.
- Try to use some already-defined parts of Phobos.
- Use a linear iteration scheme for some cases: dividing and recursing
is not a panacea.
- Maybe eliminate some 'less useful' templates, like
staticPermutations unless you have a convincing use case.


Philippe
« First   ‹ Prev
1 2