May 15, 2008 Re: plans for macros | ||||
---|---|---|---|---|
| ||||
Posted in reply to janderson | "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'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. 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 Re: plans for macros | ||||
---|---|---|---|---|
| ||||
Posted in reply to Steven Schveighoffer | 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'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.
>
> 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
>
>
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 Re: plans for macros | ||||
---|---|---|---|---|
| ||||
Posted in reply to janderson | 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 >>>>> 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. >> >> 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 >> > > 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 Re: plans for macros | ||||
---|---|---|---|---|
| ||||
Posted in reply to janderson | 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
>>>>>> 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.
>>>
>>> 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
>>>
>>
>> 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 Re: plans for macros | ||||
---|---|---|---|---|
| ||||
Posted in reply to janderson | 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 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.
>>>
>>> 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
>>>
>> 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
--------
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 Re: plans for macros | ||||
---|---|---|---|---|
| ||||
Posted in reply to boyd | 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 Re: plans for macros | ||||
---|---|---|---|---|
| ||||
Posted in reply to Steven Schveighoffer | 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 Re: plans for macros | ||||
---|---|---|---|---|
| ||||
Posted in reply to boyd | "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 Re: plans for macros | ||||
---|---|---|---|---|
| ||||
Posted in reply to Steven Schveighoffer | 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 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 -------- I see your point. Yeah, I think I'll definately turn my Log function into 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 language 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 Re: plans for macros | ||||
---|---|---|---|---|
| ||||
Posted in reply to Steven Schveighoffer | "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
|
Copyright © 1999-2021 by the D Language Foundation