Jump to page: 1 2 3
Thread overview
plans for macros
May 14, 2008
BCS
May 14, 2008
Simen Kjaeraas
May 14, 2008
BCS
May 15, 2008
Robert Fraser
May 15, 2008
janderson
May 15, 2008
janderson
May 15, 2008
janderson
May 15, 2008
janderson
May 15, 2008
janderson
May 15, 2008
janderson
May 15, 2008
janderson
May 16, 2008
Yigal Chripun
May 16, 2008
janderson
May 15, 2008
boyd
May 15, 2008
boyd
May 15, 2008
boyd
May 14, 2008
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
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
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
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 15, 2008
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 15, 2008
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
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
"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
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'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).

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
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
« First   ‹ Prev
1 2 3