www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - plans for macros

reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
I just found a very good use for macros, and I was wondering how they could 
be used to help in this situation.

If I have a log object, and that log object is supposed to evaluate its 
arguments only if the logging level allows it, checked at runtime.

So this is the ideal usage in the calling function:

if(log.isEnabledAtLevel(Information))
  log.output(someExpensiveStringBuild());

This is ideal because it only outputs at the appropriate level, and it only 
evaluates the expensive function if the log level is enabled.

However, this is very verbose, and is prone to errors.  Many log systems use 
the following method:

log.outputInformation(someExpensiveStringBuild());

Which does the if-statement for you.  However, they warn you to write your 
logging code in the first form if the code to build the output is expensive 
to avoid building the output even when it is not output.  But D has a better 
way:

class Log
{
void outputInformation(lazy string x)
{
    if(isEnabledAtLevel(Information))
      output(x);
}
}

Now, we can still use the second form, even when building the string is 
expensive.  But there are issues with this solution.  For one, lazy 
evaluation adds delegate functions wherever the logging is required, adding 
to runtime and code bloat.  Second, variadic functions would be nice for 
logging, especially with formatting, but the only way to do lazy variadic 
functions is with template tuples, so there is another lot of generated 
code, and is even more inefficient.

But a macro would solve the problem quite nicely.  A macro would evaluate 
the if statement in the calling function, and so would prevent evaluation of 
the expensive string building unless necessary, AND would require no 
delegates to do it.

The question I have is, when macros are implemented, can I have a 'class 
scoped' macro?  That is, a macro that knows what context it is supposed to 
be in, and is passed a 'this' pointer?  And will macros support variadic 
arguments?

For example, I'd like to have a macro to output formatted log information 
only if the log is enabled, but I want to call it like a member function of 
the log.

-Steve 
May 14 2008
next sibling parent reply BCS <ao pathlink.com> writes:
Reply to Steven,

 If I have a log object, and that log object is supposed to evaluate
 its arguments only if the logging level allows it, checked at runtime.
 

as a bit of an aside: this can be done using lazy void Log(uint level)(lazy char[] str) { if(current > level) RealLog.output(str()); } alias Log!(Critical) CriticalLog; ... alias Log!(Debug) DebugLog;
May 14 2008
parent reply "Simen Kjaeraas" <simen.kjaras gmail.com> writes:
BCS <ao pathlink.com> wrote:

 Reply to Steven,

 If I have a log object, and that log object is supposed to evaluate
 its arguments only if the logging level allows it, checked at runtime.

as a bit of an aside: this can be done using lazy void Log(uint level)(lazy char[] str) { if(current > level) RealLog.output(str()); } alias Log!(Critical) CriticalLog; ... alias Log!(Debug) DebugLog;

Like the man said: Steven Schveighoffer <schveiguy yahoo.com> wrote:
 But D has a better way:
 class Log
 {
 void outputInformation(lazy string x)
 {
     if(isEnabledAtLevel(Information))
       output(x);
 }
 }

It should (theoretically, at least) be possible for the compiler to inline the log function and the delegate, thus doing exactly what Steven asks. -- Simen
May 14 2008
next sibling parent BCS <ao pathlink.com> writes:
Reply to Simen,

 Like the man said:
 

Err.. Oops. I /thought/ I had read the whole thing... Note to self: Most messages don't /exactly/ fill up the screen. Check to see if there's more off the bottom. and now that I've read whole post:
 It should (theoretically, at least) be possible for the compiler to
 inline the log function and the delegate, thus doing exactly what
 Steven asks.
 

While that would address the delegate function/code bloat issue, it still doesn't address the formatting and vararg issue.
May 14 2008
prev sibling parent reply Robert Fraser <fraserofthenight gmail.com> writes:
Simen Kjaeraas wrote:
 It should (theoretically, at least) be possible for the compiler to inline
 the log function and the delegate, thus doing exactly what Steven asks.

Delegate inlining is non-trivial; AFAIK, neither DMD nor GDC does it
May 14 2008
parent janderson <askme me.com> writes:
Robert Fraser wrote:
 Simen Kjaeraas wrote:
 It should (theoretically, at least) be possible for the compiler to 
 inline
 the log function and the delegate, thus doing exactly what Steven asks.

Delegate inlining is non-trivial; AFAIK, neither DMD nor GDC does it

If the compiler could simply write a template behind the scenes (which already works) like I've shown in the other thread. How hard would that be? -Joel
May 15 2008
prev sibling parent reply janderson <askme me.com> writes:
Steven Schveighoffer wrote:
 I just found a very good use for macros, and I was wondering how they could 
 be used to help in this situation.
 
 If I have a log object, and that log object is supposed to evaluate its 
 arguments only if the logging level allows it, checked at runtime.
 
 So this is the ideal usage in the calling function:
 
 if(log.isEnabledAtLevel(Information))
   log.output(someExpensiveStringBuild());
 
 This is ideal because it only outputs at the appropriate level, and it only 
 evaluates the expensive function if the log level is enabled.
 
 However, this is very verbose, and is prone to errors.  Many log systems use 
 the following method:
 
 log.outputInformation(someExpensiveStringBuild());
 
 Which does the if-statement for you.  However, they warn you to write your 
 logging code in the first form if the code to build the output is expensive 
 to avoid building the output even when it is not output.  But D has a better 
 way:
 
 class Log
 {
 void outputInformation(lazy string x)
 {
     if(isEnabledAtLevel(Information))
       output(x);
 }
 }
 
 Now, we can still use the second form, even when building the string is 
 expensive.  But there are issues with this solution.  For one, lazy 
 evaluation adds delegate functions wherever the logging is required, adding 
 to runtime and code bloat.  Second, variadic functions would be nice for 
 logging, especially with formatting, but the only way to do lazy variadic 
 functions is with template tuples, so there is another lot of generated 
 code, and is even more inefficient.
 
 But a macro would solve the problem quite nicely.  A macro would evaluate 
 the if statement in the calling function, and so would prevent evaluation of 
 the expensive string building unless necessary, AND would require no 
 delegates to do it.
 
 The question I have is, when macros are implemented, can I have a 'class 
 scoped' macro?  That is, a macro that knows what context it is supposed to 
 be in, and is passed a 'this' pointer?  And will macros support variadic 
 arguments?
 
 For example, I'd like to have a macro to output formatted log information 
 only if the log is enabled, but I want to call it like a member function of 
 the log.
 
 -Steve 
 
 

I'm not sure if this solves your problem. Here's an interesting syntax I discovered in 1.01 (haven't checked other versions). void LogIt(alias func)() { if (true) { printf(func()); } } LogIt!( { char[] test = "test"; return test.ptr; } )(); LogIt!( { return "test"; } )(); //You couldn't do this. Unfortunately I don't want to update my compiler at this time to see if this would work in new versions. I also wonder if it could be simpled by wrapping it in something else -> thoughts? Its a pretty cool technique, essentially a inlined function pointer. If alias could be replaced with the word lazy string and have D add the extra sugar we'd be set. -Joel
May 15 2008
next sibling parent janderson <askme me.com> writes:
janderson wrote:
 Steven Schveighoffer wrote:
 I just found a very good use for macros, and I was wondering how they 
 could be used to help in this situation.

 If I have a log object, and that log object is supposed to evaluate 
 its arguments only if the logging level allows it, checked at runtime.

 So this is the ideal usage in the calling function:

 if(log.isEnabledAtLevel(Information))
   log.output(someExpensiveStringBuild());

 This is ideal because it only outputs at the appropriate level, and it 
 only evaluates the expensive function if the log level is enabled.

 However, this is very verbose, and is prone to errors.  Many log 
 systems use the following method:

 log.outputInformation(someExpensiveStringBuild());

 Which does the if-statement for you.  However, they warn you to write 
 your logging code in the first form if the code to build the output is 
 expensive to avoid building the output even when it is not output.  
 But D has a better way:

 class Log
 {
 void outputInformation(lazy string x)
 {
     if(isEnabledAtLevel(Information))
       output(x);
 }
 }

 Now, we can still use the second form, even when building the string 
 is expensive.  But there are issues with this solution.  For one, lazy 
 evaluation adds delegate functions wherever the logging is required, 
 adding to runtime and code bloat.  Second, variadic functions would be 
 nice for logging, especially with formatting, but the only way to do 
 lazy variadic functions is with template tuples, so there is another 
 lot of generated code, and is even more inefficient.

 But a macro would solve the problem quite nicely.  A macro would 
 evaluate the if statement in the calling function, and so would 
 prevent evaluation of the expensive string building unless necessary, 
 AND would require no delegates to do it.

 The question I have is, when macros are implemented, can I have a 
 'class scoped' macro?  That is, a macro that knows what context it is 
 supposed to be in, and is passed a 'this' pointer?  And will macros 
 support variadic arguments?

 For example, I'd like to have a macro to output formatted log 
 information only if the log is enabled, but I want to call it like a 
 member function of the log.

 -Steve

I'm not sure if this solves your problem. Here's an interesting syntax I discovered in 1.01 (haven't checked other versions). void LogIt(alias func)() { if (true) { printf(func()); } } LogIt!( { char[] test = "test"; return test.ptr; } )(); LogIt!( { return "test"; } )(); //You couldn't do this. Unfortunately I don't want to update my compiler at this time to see if this would work in new versions. I also wonder if it could be simpled by wrapping it in something else -> thoughts? Its a pretty cool technique, essentially a inlined function pointer. If alias could be replaced with the word lazy string and have D add the extra sugar we'd be set. -Joel

You but can do: LogIt!( { return "test".ptr; } )(); As to variadic you'd have to use the old C++ way if you where going to use this technique as I don't think alias T... works (at least it didn't in 1.01) ie: void LogIt(alias func1, alias func2)() { if (true) { LogIt!(func1)(); LogIt!(func2)(); } } PS - Yes I should probably try this on my other machine with the newer D or setup a alternative mapping for a newer version of D on this machine.
May 15 2008
prev sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
"janderson" wrote
 Steven Schveighoffer wrote:
 I just found a very good use for macros, and I was wondering how they 
 could be used to help in this situation.

 If I have a log object, and that log object is supposed to evaluate its 
 arguments only if the logging level allows it, checked at runtime.

 So this is the ideal usage in the calling function:

 if(log.isEnabledAtLevel(Information))
   log.output(someExpensiveStringBuild());

 This is ideal because it only outputs at the appropriate level, and it 
 only evaluates the expensive function if the log level is enabled.

 However, this is very verbose, and is prone to errors.  Many log systems 
 use the following method:

 log.outputInformation(someExpensiveStringBuild());

 Which does the if-statement for you.  However, they warn you to write 
 your logging code in the first form if the code to build the output is 
 expensive to avoid building the output even when it is not output.  But D 
 has a better way:

 class Log
 {
 void outputInformation(lazy string x)
 {
     if(isEnabledAtLevel(Information))
       output(x);
 }
 }

 Now, we can still use the second form, even when building the string is 
 expensive.  But there are issues with this solution.  For one, lazy 
 evaluation adds delegate functions wherever the logging is required, 
 adding to runtime and code bloat.  Second, variadic functions would be 
 nice for logging, especially with formatting, but the only way to do lazy 
 variadic functions is with template tuples, so there is another lot of 
 generated code, and is even more inefficient.

 But a macro would solve the problem quite nicely.  A macro would evaluate 
 the if statement in the calling function, and so would prevent evaluation 
 of the expensive string building unless necessary, AND would require no 
 delegates to do it.

 The question I have is, when macros are implemented, can I have a 'class 
 scoped' macro?  That is, a macro that knows what context it is supposed 
 to be in, and is passed a 'this' pointer?  And will macros support 
 variadic arguments?

 For example, I'd like to have a macro to output formatted log information 
 only if the log is enabled, but I want to call it like a member function 
 of the log.

 -Steve

I'm not sure if this solves your problem. Here's an interesting syntax I discovered in 1.01 (haven't checked other versions). void LogIt(alias func)() { if (true) { printf(func()); } } LogIt!( { char[] test = "test"; return test.ptr; } )(); LogIt!( { return "test"; } )(); //You couldn't do this. Unfortunately I don't want to update my compiler at this time to see if this would work in new versions. I also wonder if it could be simpled by wrapping it in something else -> thoughts? Its a pretty cool technique, essentially a inlined function pointer. If alias could be replaced with the word lazy string and have D add the extra sugar we'd be set.

Lazy evaluation is already supported, and already adds the extra sugar (not sure if 1.01 does though). The problem I'm trying to solve is lazy evaluation of variadic arguments. And in general, lazy evaluation is not as efficient as a macro would be -- there would be no automatic delegate generated, especially if variadic arguments need a delegate per argument, which would generate n delegates. I really think macros are the best solution to this problem, but I was wondering how easy it would be to make macros look like member functions of a class, and if they will support variadic arguments. -Steve
May 15 2008
parent reply janderson <askme me.com> writes:
Steven Schveighoffer wrote:
 "janderson" wrote
 Steven Schveighoffer wrote:
 I just found a very good use for macros, and I was wondering how they 
 could be used to help in this situation.

 If I have a log object, and that log object is supposed to evaluate its 
 arguments only if the logging level allows it, checked at runtime.

 So this is the ideal usage in the calling function:

 if(log.isEnabledAtLevel(Information))
   log.output(someExpensiveStringBuild());

 This is ideal because it only outputs at the appropriate level, and it 
 only evaluates the expensive function if the log level is enabled.

 However, this is very verbose, and is prone to errors.  Many log systems 
 use the following method:

 log.outputInformation(someExpensiveStringBuild());

 Which does the if-statement for you.  However, they warn you to write 
 your logging code in the first form if the code to build the output is 
 expensive to avoid building the output even when it is not output.  But D 
 has a better way:

 class Log
 {
 void outputInformation(lazy string x)
 {
     if(isEnabledAtLevel(Information))
       output(x);
 }
 }

 Now, we can still use the second form, even when building the string is 
 expensive.  But there are issues with this solution.  For one, lazy 
 evaluation adds delegate functions wherever the logging is required, 
 adding to runtime and code bloat.  Second, variadic functions would be 
 nice for logging, especially with formatting, but the only way to do lazy 
 variadic functions is with template tuples, so there is another lot of 
 generated code, and is even more inefficient.

 But a macro would solve the problem quite nicely.  A macro would evaluate 
 the if statement in the calling function, and so would prevent evaluation 
 of the expensive string building unless necessary, AND would require no 
 delegates to do it.

 The question I have is, when macros are implemented, can I have a 'class 
 scoped' macro?  That is, a macro that knows what context it is supposed 
 to be in, and is passed a 'this' pointer?  And will macros support 
 variadic arguments?

 For example, I'd like to have a macro to output formatted log information 
 only if the log is enabled, but I want to call it like a member function 
 of the log.

 -Steve

discovered in 1.01 (haven't checked other versions). void LogIt(alias func)() { if (true) { printf(func()); } } LogIt!( { char[] test = "test"; return test.ptr; } )(); LogIt!( { return "test"; } )(); //You couldn't do this. Unfortunately I don't want to update my compiler at this time to see if this would work in new versions. I also wonder if it could be simpled by wrapping it in something else -> thoughts? Its a pretty cool technique, essentially a inlined function pointer. If alias could be replaced with the word lazy string and have D add the extra sugar we'd be set.

Lazy evaluation is already supported, and already adds the extra sugar (not sure if 1.01 does though).

For templates? 1.01 does support lazy for as function parameters but not as template parameters.
 
 The problem I'm trying to solve is lazy evaluation of variadic arguments. 
 And in general, lazy evaluation is not as efficient as a macro would be --  
 there would be no automatic delegate generated, especially if variadic 
 arguments need a delegate per argument, which would generate n delegates.
 
 I really think macros are the best solution to this problem, but I was 
 wondering how easy it would be to make macros look like member functions of 
 a class, and if they will support variadic arguments.
 
 -Steve 
 

Templates are just as efficient as macros, particularly if u use the mixin syntax (ie force inlining of the template function itself).
 

May 15 2008
parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
"janderson" wrote
 Steven Schveighoffer wrote:
 "janderson" wrote
 Steven Schveighoffer wrote:
 I just found a very good use for macros, and I was wondering how they 
 could be used to help in this situation.

 If I have a log object, and that log object is supposed to evaluate its 
 arguments only if the logging level allows it, checked at runtime.

 So this is the ideal usage in the calling function:

 if(log.isEnabledAtLevel(Information))
   log.output(someExpensiveStringBuild());

 This is ideal because it only outputs at the appropriate level, and it 
 only evaluates the expensive function if the log level is enabled.

 However, this is very verbose, and is prone to errors.  Many log 
 systems use the following method:

 log.outputInformation(someExpensiveStringBuild());

 Which does the if-statement for you.  However, they warn you to write 
 your logging code in the first form if the code to build the output is 
 expensive to avoid building the output even when it is not output.  But 
 D has a better way:

 class Log
 {
 void outputInformation(lazy string x)
 {
     if(isEnabledAtLevel(Information))
       output(x);
 }
 }

 Now, we can still use the second form, even when building the string is 
 expensive.  But there are issues with this solution.  For one, lazy 
 evaluation adds delegate functions wherever the logging is required, 
 adding to runtime and code bloat.  Second, variadic functions would be 
 nice for logging, especially with formatting, but the only way to do 
 lazy variadic functions is with template tuples, so there is another 
 lot of generated code, and is even more inefficient.

 But a macro would solve the problem quite nicely.  A macro would 
 evaluate the if statement in the calling function, and so would prevent 
 evaluation of the expensive string building unless necessary, AND would 
 require no delegates to do it.

 The question I have is, when macros are implemented, can I have a 
 'class scoped' macro?  That is, a macro that knows what context it is 
 supposed to be in, and is passed a 'this' pointer?  And will macros 
 support variadic arguments?

 For example, I'd like to have a macro to output formatted log 
 information only if the log is enabled, but I want to call it like a 
 member function of the log.

 -Steve

I discovered in 1.01 (haven't checked other versions). void LogIt(alias func)() { if (true) { printf(func()); } } LogIt!( { char[] test = "test"; return test.ptr; } )(); LogIt!( { return "test"; } )(); //You couldn't do this. Unfortunately I don't want to update my compiler at this time to see if this would work in new versions. I also wonder if it could be simpled by wrapping it in something else -> thoughts? Its a pretty cool technique, essentially a inlined function pointer. If alias could be replaced with the word lazy string and have D add the extra sugar we'd be set.

Lazy evaluation is already supported, and already adds the extra sugar (not sure if 1.01 does though).

For templates? 1.01 does support lazy for as function parameters but not as template parameters.

Why do you need a template? A template seems like a step backwards in ease of use. I'd rather have just a lazy parameter where calling it is as easy as: LogIt("test");
 The problem I'm trying to solve is lazy evaluation of variadic arguments. 
 And in general, lazy evaluation is not as efficient as a macro would 
 be --  there would be no automatic delegate generated, especially if 
 variadic arguments need a delegate per argument, which would generate n 
 delegates.

 I really think macros are the best solution to this problem, but I was 
 wondering how easy it would be to make macros look like member functions 
 of a class, and if they will support variadic arguments.

 -Steve

Templates are just as efficient as macros, particularly if u use the mixin syntax (ie force inlining of the template function itself).

mixin would probably work, but again, the syntax is not as appealing as a macro: log.formatInfo(...); vs mixin!(log.formatInfo, ...); (don't know if this is right, I don't use mixins a lot) -Steve
May 15 2008
parent reply janderson <askme me.com> writes:
Steven Schveighoffer wrote:
 "janderson" wrote
 Steven Schveighoffer wrote:
 "janderson" wrote
 Steven Schveighoffer wrote:
 I just found a very good use for macros, and I was wondering how they 
 could be used to help in this situation.

 If I have a log object, and that log object is supposed to evaluate its 
 arguments only if the logging level allows it, checked at runtime.

 So this is the ideal usage in the calling function:

 if(log.isEnabledAtLevel(Information))
   log.output(someExpensiveStringBuild());

 This is ideal because it only outputs at the appropriate level, and it 
 only evaluates the expensive function if the log level is enabled.

 However, this is very verbose, and is prone to errors.  Many log 
 systems use the following method:

 log.outputInformation(someExpensiveStringBuild());

 Which does the if-statement for you.  However, they warn you to write 
 your logging code in the first form if the code to build the output is 
 expensive to avoid building the output even when it is not output.  But 
 D has a better way:

 class Log
 {
 void outputInformation(lazy string x)
 {
     if(isEnabledAtLevel(Information))
       output(x);
 }
 }

 Now, we can still use the second form, even when building the string is 
 expensive.  But there are issues with this solution.  For one, lazy 
 evaluation adds delegate functions wherever the logging is required, 
 adding to runtime and code bloat.  Second, variadic functions would be 
 nice for logging, especially with formatting, but the only way to do 
 lazy variadic functions is with template tuples, so there is another 
 lot of generated code, and is even more inefficient.

 But a macro would solve the problem quite nicely.  A macro would 
 evaluate the if statement in the calling function, and so would prevent 
 evaluation of the expensive string building unless necessary, AND would 
 require no delegates to do it.

 The question I have is, when macros are implemented, can I have a 
 'class scoped' macro?  That is, a macro that knows what context it is 
 supposed to be in, and is passed a 'this' pointer?  And will macros 
 support variadic arguments?

 For example, I'd like to have a macro to output formatted log 
 information only if the log is enabled, but I want to call it like a 
 member function of the log.

 -Steve

I discovered in 1.01 (haven't checked other versions). void LogIt(alias func)() { if (true) { printf(func()); } } LogIt!( { char[] test = "test"; return test.ptr; } )(); LogIt!( { return "test"; } )(); //You couldn't do this. Unfortunately I don't want to update my compiler at this time to see if this would work in new versions. I also wonder if it could be simpled by wrapping it in something else -> thoughts? Its a pretty cool technique, essentially a inlined function pointer. If alias could be replaced with the word lazy string and have D add the extra sugar we'd be set.

(not sure if 1.01 does though).

as template parameters.

Why do you need a template? A template seems like a step backwards in ease of use. I'd rather have just a lazy parameter where calling it is as easy as: LogIt("test");
 The problem I'm trying to solve is lazy evaluation of variadic arguments. 
 And in general, lazy evaluation is not as efficient as a macro would 
 be --  there would be no automatic delegate generated, especially if 
 variadic arguments need a delegate per argument, which would generate n 
 delegates.

 I really think macros are the best solution to this problem, but I was 
 wondering how easy it would be to make macros look like member functions 
 of a class, and if they will support variadic arguments.

 -Steve

syntax (ie force inlining of the template function itself).

mixin would probably work, but again, the syntax is not as appealing as a macro: log.formatInfo(...); vs mixin!(log.formatInfo, ...); (don't know if this is right, I don't use mixins a lot) -Steve

I'm not arguing against macros BTW. I do think however that templates should beable to be written as simply as: LogIt("test"); or at the very least LogIt!("test"); -Joel
May 15 2008
parent reply janderson <askme me.com> writes:
janderson wrote:
 Steven Schveighoffer wrote:
 "janderson" wrote
 Steven Schveighoffer wrote:
 "janderson" wrote
 Steven Schveighoffer wrote:
 I just found a very good use for macros, and I was wondering how 
 they could be used to help in this situation.

 If I have a log object, and that log object is supposed to 
 evaluate its arguments only if the logging level allows it, 
 checked at runtime.

 So this is the ideal usage in the calling function:

 if(log.isEnabledAtLevel(Information))
   log.output(someExpensiveStringBuild());






<Snip>
 The question I have is, when macros are implemented, can I have a 
 'class scoped' macro?  That is, a macro that knows what context it 
 is supposed to be in, and is passed a 'this' pointer?  And will 
 macros support variadic arguments?

 For example, I'd like to have a macro to output formatted log 
 information only if the log is enabled, but I want to call it like 
 a member function of the log.

 -Steve

syntax I discovered in 1.01 (haven't checked other versions). void LogIt(alias func)() { if (true) { printf(func()); } } LogIt!( { char[] test = "test"; return test.ptr; } )(); LogIt!( { return "test"; } )(); //You couldn't do this. Unfortunately I don't want to update my compiler at this time to see if this would work in new versions. I also wonder if it could be simpled by wrapping it in something else -> thoughts? Its a pretty cool technique, essentially a inlined function pointer. If alias could be replaced with the word lazy string and have D add the extra sugar we'd be set.

sugar (not sure if 1.01 does though).

not as template parameters.

Why do you need a template? A template seems like a step backwards in ease of use. I'd rather have just a lazy parameter where calling it is as easy as: LogIt("test");
 The problem I'm trying to solve is lazy evaluation of variadic 
 arguments. And in general, lazy evaluation is not as efficient as a 
 macro would be --  there would be no automatic delegate generated, 
 especially if variadic arguments need a delegate per argument, which 
 would generate n delegates.

 I really think macros are the best solution to this problem, but I 
 was wondering how easy it would be to make macros look like member 
 functions of a class, and if they will support variadic arguments.

 -Steve

mixin syntax (ie force inlining of the template function itself).

mixin would probably work, but again, the syntax is not as appealing as a macro: log.formatInfo(...); vs mixin!(log.formatInfo, ...); (don't know if this is right, I don't use mixins a lot) -Steve

I'm not arguing against macros BTW. I do think however that templates should beable to be written as simply as: LogIt("test"); or at the very least LogIt!("test"); -Joel

And it would be nice if this worked: void LogIt(lazy alias func...)() { ... } LogIt(5, "blar", 10.0f); That would be a very powerful syntax. -Joel
May 15 2008
next sibling parent reply janderson <askme me.com> writes:
janderson wrote:
 janderson wrote:
 Steven Schveighoffer wrote:
 "janderson" wrote
 Steven Schveighoffer wrote:
 "janderson" wrote
 Steven Schveighoffer wrote:
 I just found a very good use for macros, and I was wondering how 
 they could be used to help in this situation.

 If I have a log object, and that log object is supposed to 
 evaluate its arguments only if the logging level allows it, 
 checked at runtime.

 So this is the ideal usage in the calling function:

 if(log.isEnabledAtLevel(Information))
   log.output(someExpensiveStringBuild());






<Snip>
 The question I have is, when macros are implemented, can I have a 
 'class scoped' macro?  That is, a macro that knows what context 
 it is supposed to be in, and is passed a 'this' pointer?  And 
 will macros support variadic arguments?

 For example, I'd like to have a macro to output formatted log 
 information only if the log is enabled, but I want to call it 
 like a member function of the log.

 -Steve

syntax I discovered in 1.01 (haven't checked other versions). void LogIt(alias func)() { if (true) { printf(func()); } } LogIt!( { char[] test = "test"; return test.ptr; } )(); LogIt!( { return "test"; } )(); //You couldn't do this. Unfortunately I don't want to update my compiler at this time to see if this would work in new versions. I also wonder if it could be simpled by wrapping it in something else -> thoughts? Its a pretty cool technique, essentially a inlined function pointer. If alias could be replaced with the word lazy string and have D add the extra sugar we'd be set.

sugar (not sure if 1.01 does though).

but not as template parameters.

Why do you need a template? A template seems like a step backwards in ease of use. I'd rather have just a lazy parameter where calling it is as easy as: LogIt("test");
 The problem I'm trying to solve is lazy evaluation of variadic 
 arguments. And in general, lazy evaluation is not as efficient as a 
 macro would be --  there would be no automatic delegate generated, 
 especially if variadic arguments need a delegate per argument, 
 which would generate n delegates.

 I really think macros are the best solution to this problem, but I 
 was wondering how easy it would be to make macros look like member 
 functions of a class, and if they will support variadic arguments.

 -Steve

mixin syntax (ie force inlining of the template function itself).

mixin would probably work, but again, the syntax is not as appealing as a macro: log.formatInfo(...); vs mixin!(log.formatInfo, ...); (don't know if this is right, I don't use mixins a lot) -Steve

I'm not arguing against macros BTW. I do think however that templates should beable to be written as simply as: LogIt("test"); or at the very least LogIt!("test"); -Joel

And it would be nice if this worked: void LogIt(lazy alias func...)() { ... } LogIt(5, "blar", 10.0f); That would be a very powerful syntax. -Joel

Just a though. Couldn't templates simply be extended to handle macro cases so that we get supper powerful templates rather then another feature that works independently. ie I see macros working like: macro void MyMacro(foo) { foo; } MyMacro(X + 5 * 10); Where as we could make a template do the same job, void MyMacro(alias foo)() { foo; } MyMacro!(X + 5 * 10); //Compiler figures that it can drop the second () because its zero params. Any cases that you need for a macro should be put into templates instead IMHO. That will give up the flexibility to combine the power of the template with the syntax sugar of a macro. -Joel
May 15 2008
parent reply Yigal Chripun <yigal100 gmail.com> writes:
janderson wrote:
 <Snip>
 Just a though.  Couldn't templates simply be extended to handle macro
 cases so that we get supper powerful templates rather then another
 feature that works independently.
 
 ie I see macros working like:
 
 macro void MyMacro(foo)
 {
    foo;
 }
 
 MyMacro(X + 5 * 10);
 
 Where as we could make a template do the same job,
 
 void MyMacro(alias foo)()
 {
    foo;
 }
 
 MyMacro!(X + 5 * 10);  //Compiler figures that it can drop the second ()
 because its zero params.
 
 Any cases that you need for a macro should be put into templates instead
 IMHO.  That will give up the flexibility to combine the power of the
 template with the syntax sugar of a macro.
 
 -Joel

first, I'd also try using a mixin to solve this. socond, I too think that having macros as an independent new feature adds unneeded redundancy. I think that macros would provide a super set of the abilities of templates, so I suggest, instead of you proposal of adding macro capabilities to templates, to do the exact opposite. i.e. provide an "upgrade path" from your current template solution to the more general macro solution. the current syntax will still work, but the compiler would allow the user to also treat a template as a macro. the end result should be, that the client code could make use of the syntax sugar of macros even if the current implementation is a template.
May 15 2008
parent janderson <askme me.com> writes:
Yigal Chripun wrote:
 janderson wrote:
  <Snip>
  > Just a though.  Couldn't templates simply be extended to handle macro
 cases so that we get supper powerful templates rather then another
 feature that works independently.

 ie I see macros working like:

 macro void MyMacro(foo)
 {
    foo;
 }

 MyMacro(X + 5 * 10);

 Where as we could make a template do the same job,

 void MyMacro(alias foo)()
 {
    foo;
 }

 MyMacro!(X + 5 * 10);  //Compiler figures that it can drop the second ()
 because its zero params.

 Any cases that you need for a macro should be put into templates instead
 IMHO.  That will give up the flexibility to combine the power of the
 template with the syntax sugar of a macro.

 -Joel

first, I'd also try using a mixin to solve this. socond, I too think that having macros as an independent new feature adds unneeded redundancy. I think that macros would provide a super set of the abilities of templates, so I suggest, instead of you proposal of adding macro capabilities to templates, to do the exact opposite. i.e. provide an "upgrade path" from your current template solution to the more general macro solution. the current syntax will still work, but the compiler would allow the user to also treat a template as a macro. the end result should be, that the client code could make use of the syntax sugar of macros even if the current implementation is a template.

I pretty much think we are saying the same thing except on one point. The only problem I have with switching the definition part of the code to a macro syntax is that all the code we have already written in templates becomes either deprecated or alternatively we have a bloated language. I think adding a couple of extra bits of syntax sugar to templates is the way to go. As the community discover some other features that map well into "macros"/templates should the design branch yet again (ie give it a even newer name)? -Joel
May 16 2008
prev sibling parent reply boyd <gaboonviper gmx.net> writes:
On Thu, 15 May 2008 17:41:55 +0200, janderson <askme me.com> wrote:

 janderson wrote:
 Steven Schveighoffer wrote:
 "janderson" wrote
 Steven Schveighoffer wrote:
 "janderson" wrote
 Steven Schveighoffer wrote:
 I just found a very good use for macros, and I was wondering how=







 they could be used to help in this situation.

 If I have a log object, and that log object is supposed to  =







 evaluate its arguments only if the logging level allows it,  =







 checked at runtime.

 So this is the ideal usage in the calling function:

 if(log.isEnabledAtLevel(Information))
   log.output(someExpensiveStringBuild());






<Snip>
 The question I have is, when macros are implemented, can I have =







 'class scoped' macro?  That is, a macro that knows what context =







 is supposed to be in, and is passed a 'this' pointer?  And will =







 macros support variadic arguments?

 For example, I'd like to have a macro to output formatted log  =







 information only if the log is enabled, but I want to call it li=







 a member function of the log.

 -Steve







 syntax I discovered in 1.01 (haven't checked other versions).

 void LogIt(alias func)()
 {
   if (true)
   {
     printf(func());
   }
 }

 LogIt!( { char[] test =3D "test"; return test.ptr; } )();

 LogIt!( { return "test"; } )();  //You couldn't do this.

 Unfortunately I don't want to update my compiler at this time to =






 see if this would work in new versions.

 I also wonder if it could be simpled by wrapping it in something =






 else -> thoughts?  Its a pretty cool technique, essentially a  =






 inlined function pointer.

 If alias could be replaced with the word lazy string and have D a=






 the extra sugar we'd be set.






 sugar (not sure if 1.01 does though).





 not as template parameters.

Why do you need a template? A template seems like a step backwards =



 ease of use.  I'd rather have just a lazy parameter where calling it=



 is as easy as:

 LogIt("test");


 The problem I'm trying to solve is lazy evaluation of variadic  =





 arguments. And in general, lazy evaluation is not as efficient as =





 macro would be --  there would be no automatic delegate generated,=





 especially if variadic arguments need a delegate per argument, whi=





 would generate n delegates.

 I really think macros are the best solution to this problem, but I=





 was wondering how easy it would be to make macros look like member=





 functions of a class, and if they will support variadic arguments.=





 -Steve





 mixin syntax (ie force inlining of the template function itself).

mixin would probably work, but again, the syntax is not as appealing=



 as a macro:

 log.formatInfo(...);

 vs

 mixin!(log.formatInfo, ...);

 (don't know if this is right, I don't use mixins a lot)

 -Steve



 should beable to be written as simply as:
  LogIt("test");
  or at the very least
  LogIt!("test");
  -Joel

And it would be nice if this worked: void LogIt(lazy alias func...)() { ... } LogIt(5, "blar", 10.0f); That would be a very powerful syntax. -Joel

I use nearly that exact syntax in my project: debug Log(5, "blar", 10.0f); The Log function is built using a simple template: void Log(T...)(T t) { writefln(t); } As far as syntax goes that's in my opinion pretty nice. And the function= = isn't even called if debug is off. You can easily adapt it to work with = = debug levels: debug(3){ Log(whatever); Log(somethingElse); } So, this is in my opinion a problem that doesn't really need macro's to = = solve it. Cheers, Boyd
May 15 2008
parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
Yes, but turning on debug levels is a compile-time thing.  Many times, you 
want to log based on a run-time decision, i.e. a command line switch.

Your solution does not work in this case.

-Steve

"boyd" wrote
I use nearly that exact syntax in my project:

     debug Log(5, "blar", 10.0f);

The Log function is built using a simple template:

     void Log(T...)(T t)
     {
         writefln(t);
     }

As far as syntax goes that's in my opinion pretty nice. And the function
isn't even called if debug is off. You can easily adapt it to work with
debug levels:

     debug(3){
         Log(whatever);
         Log(somethingElse);
     }

So, this is in my opinion a problem that doesn't really need macro's to
solve it.

Cheers,
Boyd 
May 15 2008
parent reply boyd <gaboonviper gmx.net> writes:
What about just adding an if statement-within this kind of template?  
Wouldn't that suffice?

Using the ',' instead of concatenation can prevent a lot of complicated  
string functions. The only difference between that and macro's would be  
the function call and putting the objects on the stack. Basically the only  
advantage of macros would be that the function call is inlined.

Cheers,
Boyd

-------
On Thu, 15 May 2008 19:57:55 +0200, Steven Schveighoffer  
<schveiguy yahoo.com> wrote:

 Yes, but turning on debug levels is a compile-time thing.  Many times,  
 you
 want to log based on a run-time decision, i.e. a command line switch.

 Your solution does not work in this case.

 -Steve

 "boyd" wrote
 I use nearly that exact syntax in my project:

      debug Log(5, "blar", 10.0f);

 The Log function is built using a simple template:

      void Log(T...)(T t)
      {
          writefln(t);
      }

 As far as syntax goes that's in my opinion pretty nice. And the function
 isn't even called if debug is off. You can easily adapt it to work with
 debug levels:

      debug(3){
          Log(whatever);
          Log(somethingElse);
      }

 So, this is in my opinion a problem that doesn't really need macro's to
 solve it.

 Cheers,
 Boyd

-- Using Opera's revolutionary e-mail client: http://www.opera.com/mail/
May 15 2008
parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
"boyd" wrote
 What about just adding an if statement-within this kind of template? 
 Wouldn't that suffice?

 Using the ',' instead of concatenation can prevent a lot of complicated 
 string functions. The only difference between that and macro's would be 
 the function call and putting the objects on the stack. Basically the only 
 advantage of macros would be that the function call is inlined.

 Cheers,
 Boyd

That helps, but the arguments are still evaluated even if the if statement is false. For example: int logLevel; void Log(T...)(T t) { if(logLevel > 3) writefln(t); } class C { char[] toString() { return "This " ~ " is a C"; } } void main() { logLevel = 2; auto c = new C; Log(c); } In this case, the concatenation done in C.toString() is still evaluated, even though we aren't going to use it. That is what the lazy delegates helps with. You can 'fix' this by doing: void Log(T...)(lazy T t) {/*same implementation*/} And now, if the log level is <= 3, the delegates are never called, and no expensive concatenation is done when it won't be used. But that means that each argument has a delegate created for it, plus you are generating lots of extra template functions, when the macro way of building the code into the call site would generate almost no extra code, and would need no delegates. Not to mention the issue with static strings and IFTI. I do not deny that the problem is solvable with current language features. However, it is more correctly and *efficiently* solved with macros. I'm just trying to find out if the syntax will be palatable. -Steve
May 15 2008
next sibling parent boyd <gaboonviper gmx.net> writes:
On Thu, 15 May 2008 21:18:06 +0200, Steven Schveighoffer  =

<schveiguy yahoo.com> wrote:

 "boyd" wrote
 What about just adding an if statement-within this kind of template?
 Wouldn't that suffice?

 Using the ',' instead of concatenation can prevent a lot of complicat=


 string functions. The only difference between that and macro's would =


 the function call and putting the objects on the stack. Basically the=


 only
 advantage of macros would be that the function call is inlined.

 Cheers,
 Boyd

That helps, but the arguments are still evaluated even if the if =

 statement
 is false.

 For example:

 int logLevel;
 void Log(T...)(T t)
 {
    if(logLevel > 3)
      writefln(t);
 }

 class C
 {
    char[] toString() { return "This " ~ " is a C"; }
 }

 void main()
 {
   logLevel =3D 2;
   auto c =3D new C;
   Log(c);
 }

 In this case, the concatenation done in C.toString() is still evaluate=

 even though we aren't going to use it.  That is what the lazy delegate=

 helps with.  You can 'fix' this by doing:

 void Log(T...)(lazy T t) {/*same implementation*/}

 And now, if the log level is <=3D 3, the delegates are never called, a=

 expensive concatenation is done when it won't be used.

 But that means that each argument has a delegate created for it, plus =

 are generating lots of extra template functions, when the macro way of=

 building the code into the call site would generate almost no extra co=

 and would need no delegates.  Not to mention the issue with static  =

 strings
 and IFTI.

 I do not deny that the problem is solvable with current language  =

 features.
 However, it is more correctly and *efficiently* solved with macros.  I=

 just trying to find out if the syntax will be palatable.

 -Steve

I see your point. Yeah, I think I'll definately turn my Log function int= o = a macro when they become part of D. There is some information on macros in the presentation of the = D-conference 2007. http://s3.amazonaws.com/dconf2007/WalterAndrei.pdf It says there that names can be looked up in context of the macro = definition. It doesn't say if that scope can actually be an instance of = a = class though. I guess this question can only be answered by the D langua= ge = developers. There is also something about function declarations acting like class = members. So a function: void inc(ref int a) { a++; } could be called like this: a.inc(); Again there is no telling whether this will go for macros as well, but I= = think the chances that it eventually will are positive. It's the kind of= = syntactic sugar similar to other stuff in D that Walter seems to like. And otherwise you'll be stuck with Log(MyLog312, "logging stuff"), which= = is not that bad either. Cheers, Boyd
May 15 2008
prev sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
"Steven Schveighoffer" wrote
 That helps, but the arguments are still evaluated even if the if statement 
 is false.

 For example:

 int logLevel;
 void Log(T...)(T t)
 {
   if(logLevel > 3)
     writefln(t);
 }

 class C
 {
   char[] toString() { return "This " ~ " is a C"; }
 }

 void main()
 {
  logLevel = 2;
  auto c = new C;
  Log(c);
 }

 In this case, the concatenation done in C.toString() is still evaluated, 
 even though we aren't going to use it.  That is what the lazy delegates 
 helps with.  You can 'fix' this by doing:

Just in case someone else notices, my example was wrong, C.toString is not evaluated because writefln is the one to evaluate it. This is a better example: char[] buildSomeString() { return "hello " ~ "world"; } Log(buildSomeString()); -Steve
May 15 2008