digitalmars.D - How would you do this in D?
- Jose Armando Garcia (52/52) May 10 2011 Hey guys,
- Andrei Alexandrescu (10/35) May 10 2011 [snip]
- Jose Armando Garcia (14/55) May 10 2011 Thanks. I should have read
- Jonathan M Davis (6/15) May 10 2011 Yes, default arguments are evaluated at the call site, not where the cod...
- Jens Mueller (15/30) May 11 2011 I did some little testing (see attached file). The bar() example shows
- Don (5/33) May 11 2011 __LINE__ and __FILE__ are magical when used as default arguments in D,
- Jonathan M Davis (5/40) May 11 2011 Hmm. Good to know. Well regardless of why and how it works with __FILE__...
- so (9/13) May 11 2011 __COLUMN__ would be a very nice addition.
- Alexander (4/5) May 11 2011 BTW, I don't get it - why *scoped* variable is going to *global* names...
- Andrei Alexandrescu (3/8) May 11 2011 The macro name itself is polluting the global namespace.
- Alexander (12/13) May 11 2011 OK, this I understand. But I cannot have something like:
- Daniel Gibson (15/79) May 10 2011 1. For ACTION you could use a delegate/lambda
- Daniel Gibson (22/24) May 10 2011 What about:
Hey guys, I am trying to create a function that return true or executes "something" the n-th time it is called from a specific call site. How would you do that in D? In C we can do that with the help of pre-processor macros. E.g.: --- #include <assert.h> #define EVERY(N, ACTION) { static int counter = 0; if(++counter > (N)) counter -= (N); if(counter == 1) (ACTION); } int main() { int i = 0; int j = 0; while(i < 10) { EVERY(10, ++j); EVERY(2, ++i); } assert(j == 2); assert(i == 10); } --- In D, I hacked the following implementation. I don't like this implementation for a log of reason... Am I missing some D feature? Can someone do better? --- int[string] map; bool every(string file = __FILE__, int line = __LINE__)(int time) { // assume file ~ "+" ~ to!string(line) is unique // assumption could be removed by using a struct string key = file ~ "+" ~ to!string(line); map[key] += 1; if(map[key] > time) map[key] -= time; return map[key] == 1; } unittest { auto i = 0; auto j = 0; while(i < 10) { if(every(10)) ++j; if(every(2)) ++i; } assert(j == 2); assert(i == 10); } void main() {} --- Thanks! -Jose
May 10 2011
On 5/10/11 7:32 PM, Jose Armando Garcia wrote:Hey guys, I am trying to create a function that return true or executes "something" the n-th time it is called from a specific call site. How would you do that in D? In C we can do that with the help of pre-processor macros. E.g.: --- #include<assert.h> #define EVERY(N, ACTION) { static int counter = 0; if(++counter> (N)) counter -= (N); if(counter == 1) (ACTION); } int main() { int i = 0; int j = 0; while(i< 10) { EVERY(10, ++j); EVERY(2, ++i); } assert(j == 2); assert(i == 10); } --- In D, I hacked the following implementation. I don't like this implementation for a log of reason... Am I missing some D feature? Can someone do better?[snip] Just use a static variable inside a function parameterized by __FILE__ and __LINE__. Indeed the drawback is that two every() calls in one line will share that static. I consider it a small matter. If it becomes a bear we may as well add __COLUMN__ or something similar. Note that the macro version has other, arguably larger, drawbacks - e.g. it can't be used as an expression, evaluates the limit multiple times. pollutes the global namespace etc. Andrei
May 10 2011
Thanks. I should have read http://www.digitalmars.com/d/2.0/template.html more carefully. "Multiple instantiations of a TemplateDeclaration with the same TemplateArgumentList, before implicit conversions, all will refer to the same instantiation." The default values which are evaluated at the call site are part of the TemplateArgumentList. On Tue, May 10, 2011 at 9:52 PM, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:On 5/10/11 7:32 PM, Jose Armando Garcia wrote:))Hey guys, I am trying to create a function that return true or executes "something" the n-th time it is called from a specific call site. How would you do that in D? In C we can do that with the help of pre-processor macros. E.g.: --- #include<assert.h> #define EVERY(N, ACTION) { static int counter =3D 0; if(++counter> =A0(N=dcounter -=3D (N); if(counter =3D=3D 1) (ACTION); } int main() { =A0 =A0int i =3D 0; =A0 =A0int j =3D 0; =A0 =A0while(i< =A010) =A0 =A0{ =A0 =A0 =A0 EVERY(10, ++j); =A0 =A0 =A0 EVERY(2, ++i); =A0 =A0} =A0 =A0assert(j =3D=3D 2); =A0 =A0assert(i =3D=3D 10); } --- In D, I hacked the following implementation. I don't like this implementation for a log of reason... Am I missing some D feature? Can someone do better?[snip] Just use a static variable inside a function parameterized by __FILE__ an=__LINE__. Indeed the drawback is that two every() calls in one line will share that static. I consider it a small matter. If it becomes a bear we =mayas well add __COLUMN__ or something similar. Note that the macro version has other, arguably larger, drawbacks - e.g. =itcan't be used as an expression, evaluates the limit multiple times. pollu=testhe global namespace etc. Andrei
May 10 2011
On 2011-05-10 18:06, Jose Armando Garcia wrote:Thanks. I should have read http://www.digitalmars.com/d/2.0/template.html more carefully. "Multiple instantiations of a TemplateDeclaration with the same TemplateArgumentList, before implicit conversions, all will refer to the same instantiation." The default values which are evaluated at the call site are part of the TemplateArgumentList.Yes, default arguments are evaluated at the call site, not where the code is declared. I believe that C++ has the opposite behavior, so it's not uncommon that people miss that. It's _very_ useful though - particularly when dealing with __FILE__ and __LINE__. - Jonathan M Davis
May 10 2011
Content-Disposition: inline Jonathan M Davis wrote:On 2011-05-10 18:06, Jose Armando Garcia wrote:I did some little testing (see attached file). The bar() example shows that default arguments are evaluated at call site (even in C++). If it was only evaluated when declared it would always return 1. But __LINE__ does not work as in D. I believe that is due to __LINE__ being a macro in C whereas in D it is evaluated at instantiation time (i.e. it is not text replacement). So it seems that instantiation of default arguments is the same in D and C++. The difference is that __LINE__ and __FILE__ are different things in C++ and D. In C++ there is no such thing as evaluating __LINE__. Or let's say they are constant expressions (due to textual replacement) where in D they are evaluated differently depending on the context. Does this make sense? JensThanks. I should have read http://www.digitalmars.com/d/2.0/template.html more carefully. "Multiple instantiations of a TemplateDeclaration with the same TemplateArgumentList, before implicit conversions, all will refer to the same instantiation." The default values which are evaluated at the call site are part of the TemplateArgumentList.Yes, default arguments are evaluated at the call site, not where the code is declared. I believe that C++ has the opposite behavior, so it's not uncommon that people miss that. It's _very_ useful though - particularly when dealing with __FILE__ and __LINE__.
May 11 2011
Jens Mueller wrote:Jonathan M Davis wrote:__LINE__ and __FILE__ are magical when used as default arguments in D, for exactly this use case, since it is *extremely* useful. In every other case they behave as in C++. (IIRC the magic is not even implemented for default arguments of __LINE__ + 0, only for __LINE__).On 2011-05-10 18:06, Jose Armando Garcia wrote:I did some little testing (see attached file). The bar() example shows that default arguments are evaluated at call site (even in C++). If it was only evaluated when declared it would always return 1. But __LINE__ does not work as in D. I believe that is due to __LINE__ being a macro in C whereas in D it is evaluated at instantiation time (i.e. it is not text replacement). So it seems that instantiation of default arguments is the same in D and C++. The difference is that __LINE__ and __FILE__ are different things in C++ and D. In C++ there is no such thing as evaluating __LINE__. Or let's say they are constant expressions (due to textual replacement) where in D they are evaluated differently depending on the context. Does this make sense?Thanks. I should have read http://www.digitalmars.com/d/2.0/template.html more carefully. "Multiple instantiations of a TemplateDeclaration with the same TemplateArgumentList, before implicit conversions, all will refer to the same instantiation." The default values which are evaluated at the call site are part of the TemplateArgumentList.Yes, default arguments are evaluated at the call site, not where the code is declared. I believe that C++ has the opposite behavior, so it's not uncommon that people miss that. It's _very_ useful though - particularly when dealing with __FILE__ and __LINE__.
May 11 2011
On 2011-05-11 03:59, Don wrote:Jens Mueller wrote:Hmm. Good to know. Well regardless of why and how it works with __FILE__ and __LINE__, it's definitely fantastic that they do. It is indeed _extremely_ useful. - Jonathan M DavisJonathan M Davis wrote:__LINE__ and __FILE__ are magical when used as default arguments in D, for exactly this use case, since it is *extremely* useful. In every other case they behave as in C++. (IIRC the magic is not even implemented for default arguments of __LINE__ + 0, only for __LINE__).On 2011-05-10 18:06, Jose Armando Garcia wrote:I did some little testing (see attached file). The bar() example shows that default arguments are evaluated at call site (even in C++). If it was only evaluated when declared it would always return 1. But __LINE__ does not work as in D. I believe that is due to __LINE__ being a macro in C whereas in D it is evaluated at instantiation time (i.e. it is not text replacement). So it seems that instantiation of default arguments is the same in D and C++. The difference is that __LINE__ and __FILE__ are different things in C++ and D. In C++ there is no such thing as evaluating __LINE__. Or let's say they are constant expressions (due to textual replacement) where in D they are evaluated differently depending on the context. Does this make sense?Thanks. I should have read http://www.digitalmars.com/d/2.0/template.html more carefully. "Multiple instantiations of a TemplateDeclaration with the same TemplateArgumentList, before implicit conversions, all will refer to the same instantiation." The default values which are evaluated at the call site are part of the TemplateArgumentList.Yes, default arguments are evaluated at the call site, not where the code is declared. I believe that C++ has the opposite behavior, so it's not uncommon that people miss that. It's _very_ useful though - particularly when dealing with __FILE__ and __LINE__.
May 11 2011
Just use a static variable inside a function parameterized by __FILE__ and __LINE__. Indeed the drawback is that two every() calls in one line will share that static. I consider it a small matter. If it becomes a bear we may as well add __COLUMN__ or something similar.__COLUMN__ would be a very nice addition. Not an everyday usage but there was this unorthodox approach on UI coding, immediate mode, which i quite like. The problem was the id generation. There were solutions, but either not enough or too verbose. With default template args and __F,L,C__ we would have a pretty good solution for this particular problem and similar issues. I don't know, maybe there are already some neat solutions to this in D.
May 11 2011
On 11.05.2011 02:52, Andrei Alexandrescu wrote:Note that the macro version has other, arguably larger, drawbacks - e.g. it can't be used as an expression, evaluates the limit multiple times. pollutes the global namespace etc.BTW, I don't get it - why *scoped* variable is going to *global* namespace when declared "static"? This, IMHO, defeats the value and purpose of scoping... /Alexander
May 11 2011
On 05/11/2011 12:07 PM, Alexander wrote:On 11.05.2011 02:52, Andrei Alexandrescu wrote:The macro name itself is polluting the global namespace. AndreiNote that the macro version has other, arguably larger, drawbacks - e.g. it can't be used as an expression, evaluates the limit multiple times. pollutes the global namespace etc.BTW, I don't get it - why *scoped* variable is going to *global* namespace when declared "static"? This, IMHO, defeats the value and purpose of scoping... /Alexander
May 11 2011
On 11.05.2011 20:07, Andrei Alexandrescu wrote:The macro name itself is polluting the global namespace.OK, this I understand. But I cannot have something like: { static int i = 0; } { static int i = 1; } This produces linker warning: io.o:(.tdata.+0x0): multiple definition of `void io.main(immutable(char)[][]).int i' Sure, this defined in function scope, not globally, but anyway... /Alexander
May 11 2011
Am 11.05.2011 02:32, schrieb Jose Armando Garcia:Hey guys, I am trying to create a function that return true or executes "something" the n-th time it is called from a specific call site. How would you do that in D? In C we can do that with the help of pre-processor macros. E.g.: --- #include <assert.h> #define EVERY(N, ACTION) { static int counter = 0; if(++counter > (N)) counter -= (N); if(counter == 1) (ACTION); } int main() { int i = 0; int j = 0; while(i < 10) { EVERY(10, ++j); EVERY(2, ++i); } assert(j == 2); assert(i == 10); } --- In D, I hacked the following implementation. I don't like this implementation for a log of reason... Am I missing some D feature? Can someone do better? --- int[string] map; bool every(string file = __FILE__, int line = __LINE__)(int time) { // assume file ~ "+" ~ to!string(line) is unique // assumption could be removed by using a struct string key = file ~ "+" ~ to!string(line); map[key] += 1; if(map[key] > time) map[key] -= time; return map[key] == 1; } unittest { auto i = 0; auto j = 0; while(i < 10) { if(every(10)) ++j; if(every(2)) ++i; } assert(j == 2); assert(i == 10); } void main() {} --- Thanks! -Jose1. For ACTION you could use a delegate/lambda 2. Using a map is an ugly hack IMHO. IMHO it's not necessary, because the code generated by the template will be unique if __FILE__ and __LINE__ are unique (as you assume), so you could use a static int like in C. However, it's probably smarter and more clean to have struct (or maybe class) containing the counter, the delegate and the threshold (10 for every 10 etc) and a method incrementing the counter and invoking the delegate. The code isn't as short as the C version, but the implementation is more clean IMHO: http://pastebin.com/XVSnALbq There may be a more clever template-trick, however. Cheers, - Daniel
May 10 2011
Am 11.05.2011 02:56, schrieb Daniel Gibson:There may be a more clever template-trick, however.What about: void EVERY(int threshold, alias action, string file = __FILE__, int line = __LINE__)() { static int cnt; ++cnt; if(cnt==threshold) { action(); cnt=0; } } void main() { int i,j; while(i<10) { EVERY!(10, {++j;} )(); EVERY!(2, {++i;} ); // last () was optional } assert(j==2); assert(i==10); } :-)
May 10 2011