Re: [static] foreach scope, template declaration ?

2014-09-26 Thread SlomoTheBrave via Digitalmars-d-learn

On Friday, 26 September 2014 at 11:16:01 UTC, Mathias LANG wrote:
On Thursday, 25 September 2014 at 23:08:53 UTC, SlomoTheBrave 
wrote:
a way around this is not to use anySatisfy nor the template, 
for example this works as expected:


[...]



My problem is that in this example, attributes are in the same 
order as the parameter. But this come from a code generator, 
which takes class defined by the user, so I have to assume they 
might not be in the correct order :)




Your problem is that you absolutely want to do some idiomatic D2 
with std, instead, using a home-cooked static function it would 
work fine, as demonstrated by my example (currently you use an 
eponyme template, so basically it's just a function). If your aim 
is to highlight a bug then fill a bug report.


Re: [static] foreach scope, template declaration ?

2014-09-26 Thread Mathias LANG via Digitalmars-d-learn
On Thursday, 25 September 2014 at 23:08:53 UTC, SlomoTheBrave 
wrote:
a way around this is not to use anySatisfy nor the template, 
for example this works as expected:


[...]



My problem is that in this example, attributes are in the same 
order as the parameter. But this come from a code generator, 
which takes class defined by the user, so I have to assume they 
might not be in the correct order :)


which is less abstruse. However I don't know if it has hurted 
your eyes too but the output lines order shows there is a 
problem too:



Current attr is: p1
Instantiated for: p1
Instantiated for: p2
Instantiated for: p3
Current attr is: p2
Current attr is: P3


instead of


Current attr is: p1
Instantiated for: p1
Current attr is: p2
Instantiated for: p2
Current attr is: P3
Instantiated for: p3


o!o


On Thursday, 25 September 2014 at 23:37:11 UTC, Ali Çehreli wrote:


Surprisingly, that indicates that anySatisfy did instantiate 
CmpName with all three string values, meaning that perhaps we 
don't have shortcut behavior for 'bool' eponymous templates.


This is documented 
(http://dlang.org/phobos/std_typetuple.html#.anySatisfy): 
Evaluation is *not* short-circuited if a true result is 
encountered; the template predicate must be instantiable with all 
the given items.


When I use myAnySatisfy instead of anySatisfy, I see that I am 
right: The last expression above does not stop instantiating 
after "p1". In other words, even though myAnySatisfy!(F, T[$/2 
..  $ ] is unnecessary (because the first part of || is already 
'true'), it gets instantiated anyway.


[...]

This looks like an enhancement request.

Ali


I didn't consider this aspect, and there's definitely ground for 
optimization. However, let's say I replace the definition of 
MyClass with:



class MyClass {
@(UDAStruct("p3"), UDAStruct("P2"), UDAStruct("p1")) // P2 is 
a typo

  void func(int p1, string p2, float p3) {}
}



In this case, anySatisfy is right to instantiate all 3 templates 
on the first iteration. Here's the result:



$ dmd -unittest -run bug.d
Current attr is: p3
Instantiated for: p1
Instantiated for: p2
Instantiated for: p3
Current attr is: P2
Current attr is: p1


There is no needless instantiation in this case, yet we still 
have the same behaviour (static assert not triggered).


Re: [static] foreach scope, template declaration ?

2014-09-26 Thread via Digitalmars-d-learn

On Thursday, 25 September 2014 at 23:37:11 UTC, Ali Çehreli wrote:
Surprisingly, that indicates that anySatisfy did instantiate 
CmpName with all three string values, meaning that perhaps we 
don't have shortcut behavior for 'bool' eponymous templates.


Yes, that's the case (not just for eponymous templates, but I 
can't remember the details). There was a discussion about it on 
digitalmars.D a few months ago.


Re: [static] foreach scope, template declaration ?

2014-09-25 Thread Ali Çehreli via Digitalmars-d-learn

On 09/25/2014 04:08 PM, SlomoTheBrave wrote:

> On Thursday, 25 September 2014 at 22:11:20 UTC, Mathias LANG wrote:
>> I'm a bit puzzled with the following behavior:
>>
>> 
>> import std.typetuple, std.traits;
>>
>> struct UDAStruct {
>> string identifier;
>> }
>>
>> class MyClass {
>> @(UDAStruct("p1"), UDAStruct("p2"), UDAStruct("P3")) // P3 is a typo
>>   void func(int p1, string p2, float p3) {}
>> }
>>
>> unittest {
>> alias Func = MyClass.func;
>> enum ParamNames = ParameterIdentifierTuple!Func;
>> enum ParamAttr = __traits(getAttributes, Func);
>>
>> foreach (attr; ParamAttr) {
>> template CmpName(string PName) {
>> pragma(msg, "Instantiated for: "~PName);
>> enum CmpName = (PName == attr.identifier);
>> }
>> pragma(msg, "Current attr is: "~attr.identifier);
>> static assert(anySatisfy!(CmpName, ParamNames));

The first invocation of that line will instantiate CmpName with 
ParamNames, which happens to be a TypeTuple of "p1", "p2", and "p3".


> the output lines order shows there is a problem too:
>
>> Current attr is: p1
>> Instantiated for: p1
>> Instantiated for: p2
>> Instantiated for: p3

Surprisingly, that indicates that anySatisfy did instantiate CmpName 
with all three string values, meaning that perhaps we don't have 
shortcut behavior for 'bool' eponymous templates.


Copying and instrumenting anySatisfy's implementation:

template myAnySatisfy(alias F, T...)
{
pragma(msg, "myAnySatisfy with "~[ T ]);
static if(T.length == 0)
{
enum myAnySatisfy = false;
pragma(msg, "length == 0 "~myAnySatisfy);
}
else static if (T.length == 1)
{
enum myAnySatisfy = F!(T[0]);
pragma(msg, "length == 1 "~myAnySatisfy);
}
else
{
enum myAnySatisfy =
myAnySatisfy!(F, T[ 0  .. $/2]) ||
myAnySatisfy!(F, T[$/2 ..  $ ]);
pragma(msg, "else "~myAnySatisfy);
}
}

When I use myAnySatisfy instead of anySatisfy, I see that I am right: 
The last expression above does not stop instantiating after "p1". In 
other words, even though myAnySatisfy!(F, T[$/2 ..  $ ] is unnecessary 
(because the first part of || is already 'true'), it gets instantiated 
anyway.


Current attr is: p1
["myAnySatisfy with ", "p1", "p2", "p3"]
["myAnySatisfy with ", "p1"]
Instantiated for: p1
length == 1 
["myAnySatisfy with ", "p2", "p3"]
["myAnySatisfy with ", "p2"]
Instantiated for: p2
length == 1
["myAnySatisfy with ", "p3"]
Instantiated for: p3
length == 1
else
else 
Current attr is: p2
Current attr is: P3

This looks like an enhancement request.

Ali



Re: [static] foreach scope, template declaration ?

2014-09-25 Thread SlomoTheBrave via Digitalmars-d-learn
On Thursday, 25 September 2014 at 22:11:20 UTC, Mathias LANG 
wrote:

I'm a bit puzzled with the following behavior:


import std.typetuple, std.traits;

struct UDAStruct {
string identifier;
}

class MyClass {
@(UDAStruct("p1"), UDAStruct("p2"), UDAStruct("P3")) // P3 
is a typo

  void func(int p1, string p2, float p3) {}
}

unittest {
alias Func = MyClass.func;
enum ParamNames = ParameterIdentifierTuple!Func;
enum ParamAttr = __traits(getAttributes, Func);

foreach (attr; ParamAttr) {
template CmpName(string PName) {
pragma(msg, "Instantiated for: "~PName);
enum CmpName = (PName == attr.identifier);
}
pragma(msg, "Current attr is: "~attr.identifier);
static assert(anySatisfy!(CmpName, ParamNames));
}

// Foreach does introduce a scope, as this produce no 
compile time error.

template CmpName(string test) { enum CmpName = test; }
static assert(CmpName!"?" == "?");
}

void main() {}


The output is (FE 2.066 & 2.065 tested):
148 geod24@barsoom2 ~ % dmd -unittest -run test.d
Current attr is: p1
Instantiated for: p1
Instantiated for: p2
Instantiated for: p3
Current attr is: p2
Current attr is: P3

Obviously one call tell it's not what I expected. It looks like 
DMD is reusing the instantiations of the template of the first 
loop for p2 and P3.
The 2 lines at the end check that foreach does introduce a 
scope, but it behaves differently than what we're use to.


Is there a way around this ?
I tried to move CmpName outside the loop, then declare `alias 
Cmp(string x) = CmpName(attr, x);` in the loop, but it doesn't 
help (I guess the same thing happens?).


a way around this is not to use anySatisfy nor the template, for 
example this works as expected:


import std.typetuple, std.traits;

struct UDAStruct {
string identifier;
}

class MyClass {
@(UDAStruct("p1"), UDAStruct("p2"), UDAStruct("P3")) // P3 
isa typo

  void func(int p1, string p2, float p3) {}
}

--
void main(string[] args){

alias Func = MyClass.func;
enum ParamNames = ParameterIdentifierTuple!Func;
enum ParamAttr = __traits(getAttributes, Func);

foreach(i,attr; ParamAttr) {
static assert(attr.identifier == ParamNames[i], 
attr.identifier);

}
}
--

which is less abstruse. However I don't know if it has hurted 
your eyes too but the output lines order shows there is a problem 
too:



Current attr is: p1
Instantiated for: p1
Instantiated for: p2
Instantiated for: p3
Current attr is: p2
Current attr is: P3


instead of


Current attr is: p1
Instantiated for: p1
Current attr is: p2
Instantiated for: p2
Current attr is: P3
Instantiated for: p3


o!o