October 05, 2010
Philippe Sigaud <philippe.sigaud at gmail.com> wrote:
> 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.

Forgive me, but I'll omit answering to your individual comments against the subdivision.  I had the following thing in mind.

I implemented most templates with linear recursion at first.  But it hit compiler's limit (= 500) of recursive template instantiation when testing combinatorial algorithms.  The limitation makes sense because the compiler actually recurses without tail-recursion optimization.

I think a library should hide such kind of defects from user code. That's why I implemented most templates with the subdivision scheme, which reduced recursion depth to log(n).

That said, I must agree that it complicates things.  I'm sorry for having you read such a weird code.  If needed, I'll make them revert to adopt straightforward linear recursion.


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

If you are saying about private templates such as _staticReplace, okay, I'll follow the convention.


> 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.

I'm happy with TypeTuple personally.  But now is the chance to fix the misnomer, isn't it?  I'll post another topic on the messy situation around the tuple nomenclature.


> 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)

Isn't it a matter of taste?


> 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])?

That's for allowing staticMap!(q{a.sizeof }, ...).  It's indeed ugly and
I'll fix as follows.

template staticMap(alias map, seq...);
template staticMap(string map, seq...);


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

Yes.  staticFilter should consistently return a tuple.


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

Oh, it's your StaticScan.  Could you contribute your templates?
(SegmentTypes too.)


> 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.

Yes, m is the arity.  I know dranges has a template that parses arity out of a stringof property.  But is it reliable to parse stringof?  Its content is unspecified and it sometimes lies.

Also, consider this:
----------
import dranges.templates;

template isStaticArray(T : T[N], size_t N)
{
    enum isStaticArray = true;
}
static assert(TemplateArity!isStaticArray == 2);
----------
TemplateArity reports isStaticArray as a binary template, but it's effectively a unary one.  I suspect that template arity can't be determined due to argument deduction and default arguments.


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

Yeah.


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

The same problem about template's arity arises.


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

I didn't use staticFilter to avoid unnecessary tuple allocation inside the compiler.  Maybe I'm too much worrying such kind of things.


> l. 352 (_staticReplace(tr...): what if tr.length is not 2?

It's an internal stuff and tr.length must be always 2.

> Why not just do _staticReplace(from,to)?

It doesn't work with symbols or constants if declared so.  I used template tuple parameters as wildcard parameters.


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

No, it can't work when tr[0] is a literal constant.  For instance:
----------
template A(tr...)
{
    alias tr[0] from;
    // Error: alias test.A!("x","y").from cannot alias an expression "x"
}
alias A!("x", "y") a;
----------
It errors because tr[0] is a literal.  Indeed, this should not work:

    alias "x" from;

Identity gives a symbol to the literal constant and makes it work.


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

It's for reducing recursion depth.  staticMost can be computed with log(n) recursions, whereas staticReduce can't.


> l. 384 & 388: why Identity?

It doesn't work if a tuple contains literal constants as I noted above.


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

No ambiguity.  It's specifically stated in the document (template.html):

  If both a template with a tuple parameter and a template without a
  tuple parameter exactly match a template instantiation, the template
  without a TemplateTupleParameter is selected.

You can expect pattern-match semantics here. :-)


> 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.

It breaks stability of the sorting algorithm.  Comparison must be in that order, or you'll get wrong results:

staticSort!(q{ a.sizeof < b.sizeof }, int, byte, char)
  = (char, byte, int)  // no

In this case, the expected result is (byte, char, int).


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

staticUniq only eliminates consecutive duplicates with O(n) comparisons,
while staticRemoveDuplicates eliminates all duplicates with O(n^2).


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

Okay, I'll stick with < 2.


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

You mean l. 674?  I think staticStride should consistently return a tuple, not forcing user to handle the special case of 1-element.

  staticStride!(3, int, double, string, bool) = (int, bool)
  staticStride!(3, int, double) = int  // why?
  staticStride!(3) = ()

Do you really want the second case to be special: a bare int?


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

Agreed.


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

Could you elaborate what staticZipWith is?


> l. 763: staticPermutations: do you have a use case in mind?

I regard the combinatorial algorithms as helpers for systematic tests.


> l. 765: (5 is the limit). Really? 120 5-tuplets is the limit?

It's too slow to list 6! permutations with that implementation.  An iterative algorithm might reduce the time cost, but it would instead hit the limit of recursion depth and eventually limited up to 5!


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

My bad, I forgot to replace it with Wrap.  For your curiosity, here's a simplified metaArray:

  metaArray
  http://gist.github.com/610238

I abandoned it because of compiler bugs and maybe-specs.


> 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)

Wait, std.typecons.Tuple can't hold constants.  This doesn't work: Tuple!("foo", "bar", "baz").  I really want to wrap types and constants with a consistent manner.

Consider parsing template parameters (int, "x", 100, double, "y", 200) which represents  "int x = 100;"  and  "double y = 200;".

You may want to use staticSegment!(3, ...) and get a tuple of tuples
(Wrap!(int, "x", 100) , Wrap!(double, "y", 200)).  Now it's very easy
to handle each group in the segmented form.  That's a use case.


> 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?

Yes.  It could be "is(Wrap!A == Wrap!B)" if Wrap were a type.

I wanted to make Wrap a type, but the optlink bug 4904 worries me about type information generated for every Wrap instantiation... ugh!

  http://d.puremagic.com/issues/show_bug.cgi?id=4904


> l. 1271 & 1280 (templateAnd, templateOr): These are quite useful, good
> idea to add them.

Thanks.  Since we don't have template literals, this kind of composers would be vital.  Maybe we'll eventually need more.

> I have the basis of a 'type pattern' module, to look for patterns in tuples, like for regexes. Maybe that could interest someone.

Cool, it would vastly reduce ad-hoc tuple parsing code.  I want to eliminate ones in std.typecons.Tuple and std.bitmanip.bitfields!


> Btw, I tested Robert's suggestion to put things in a struct called meta, and it worked:
> 
> ...snip...
> 
> I find meta.* much cleaner than static* and such.

I agree.  It's a reasonable solution at this point.


Shin
October 10, 2010
Hey Shin, I've not forgotten you! Sorry for not coming back earlier, but work was horrifying all week. I totally crashed on the week end. And I'm pretty sure it'll be that way ofr many weeks.

I'll answer you in time, I find most of your arguments quite compelling. I'll also put my type patterns module online.

Philippe
October 11, 2010
Philippe Sigaud <philippe.sigaud at gmail.com> wrote:
> Hey Shin, I've not forgotten you! Sorry for not coming back earlier, but work was horrifying all week. I totally crashed on the week end. And I'm pretty sure it'll be that way ofr many weeks.
> 
> I'll answer you in time, I find most of your arguments quite compelling. I'll also put my type patterns module online.

Thanks for the reply!  Don't worry, this enhancement can wait.  It'll
take some time to polish the code and design anyway; and fortunately
or unfortunately, there's not much of general interest in the topic. ;-)


Shin
October 11, 2010
On Mon, Oct 11, 2010 at 06:11, Shin Fujishiro <rsinfu at gmail.com> wrote:
> Thanks for the reply! ?Don't worry, this enhancement can wait. ?It'll
> take some time to polish the code and design anyway; and fortunately
> or unfortunately, there's not much of general interest in the topic. ;-)

I'd also like to see if the tuple threads will go somewhere.

If more people are exposed to the idea of tuples as *collection* of heterogeneous values (emphasis mine), they may be more interested by a way to use them as real collections: map a function on them, filter them, etc.
January 02, 2011
I think this module has good potential. The code is surprisingly clean, considering it does quite wacky stuff :o).

Shin, std.meta is big enough to need a formal review. That means you need to clean up the code thoroughly, provide solid documentation and examples, and mind the feedback you get from digitalmars.d. Refer to http://www.boost.org/community/reviews.html for the model we want to follow. I'll be glad to manage the review process.


Andrei

On 9/28/10 2:50 AM, Shin Fujishiro 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.
>
> 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
> _______________________________________________
> phobos mailing list
> phobos at puremagic.com
> http://lists.puremagic.com/mailman/listinfo/phobos
January 02, 2011
One more thing - Struct does what Tuple does, so it's redundant.

Andrei

On 9/28/10 2:50 AM, Shin Fujishiro 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.
>
> 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
> _______________________________________________
> phobos mailing list
> phobos at puremagic.com
> http://lists.puremagic.com/mailman/listinfo/phobos
January 02, 2011
On 9/27/10 1:58 PM, Philippe Sigaud wrote:
> 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.

Looks like much of this code could be integrated with Shin's. Any chance you could work out a joint proposal?

Andrei
1 2
Next ›   Last »