Thread overview | |||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|
|
March 07, 2019 Aliasing a mixin (or alternative ways to profile a scope) | ||||
---|---|---|---|---|
| ||||
Hello, I am currently porting the frontend of my instrumenting profiler to D. It features a C++-makro that profiles the time between entering and leaving a scope (achieved with con-/destructors in C++). Since D has scopeguards, I hoped to achieve this by creating a mixin that generates the following code: measure("func1"); scope(exit) measure("func1"); Since I of course don't want to type a mixin for that everytime I want to use it, I tried to alias it: import std.meta : Alias; alias profile_scope(string name) = Alias!(mixin("measure(\"" ~ name ~ "\"); scope(exit) measure(\"" ~ name ~ "\");")); I expected this to generate the code above by typing profile_scope("func1") in my programm. However the compiler (dmd) gives me the following error: source\main.d(24): Error: template plattform.profile_scope cannot deduce function from argument types !()(string), candidates are: source\plattform.d(262): plattform.profile_scope(string name) This looks like a deduction/overload kind of error, which has me completly confused since there is no other identifier of the name "profile_scope" in my programm and the error message shows only one candidate. Is there any way I can achive generating those two statements using only something that effectively looks like a function call/C-macro with an argument? |
March 07, 2019 Re: Aliasing a mixin (or alternative ways to profile a scope) | ||||
---|---|---|---|---|
| ||||
Posted in reply to Simon | On Thursday, 7 March 2019 at 20:07:27 UTC, Simon wrote:
> measure("func1");
> scope(exit) measure("func1");
I would suggest just using a struct. Make its constructor do the first measure, and its destructor do the second measure.
I betcha you can avoid mixin entirely.
|
March 07, 2019 Re: Aliasing a mixin (or alternative ways to profile a scope) | ||||
---|---|---|---|---|
| ||||
Posted in reply to Simon | Am 07.03.19 um 21:07 schrieb Simon: > Hello, > > I am currently porting the frontend of my instrumenting profiler to D. It features a C++-makro that profiles the time between entering and leaving a scope (achieved with con-/destructors in C++). Since D has scopeguards, I hoped to achieve this by creating a mixin that generates the following code: > > measure("func1"); > scope(exit) measure("func1"); > > Since I of course don't want to type a mixin for that everytime I want to use it, I tried to alias it: > > import std.meta : Alias; > alias profile_scope(string name) = Alias!(mixin("measure(\"" ~ name ~ > "\"); scope(exit) measure(\"" ~ name ~ "\");")); > > I expected this to generate the code above by typing > profile_scope("func1") in my programm. However the compiler (dmd) gives > me the following error: > > source\main.d(24): Error: template plattform.profile_scope cannot deduce > function from argument types !()(string), candidates are: > source\plattform.d(262): plattform.profile_scope(string name) > > This looks like a deduction/overload kind of error, which has me completly confused since there is no other identifier of the name "profile_scope" in my programm and the error message shows only one candidate. > > Is there any way I can achive generating those two statements using only something that effectively looks like a function call/C-macro with an argument? The error you are seeing is due to the fact that you pass "func1" as runtime parameter instead of as a teamplate parameter. You would need to do `profile_scope!("func1");`. However, this will still not work and you'll get an error message similar to this: ``` main.d(4): Error: incomplete mixin expression writeln("func1"); scope(exit) writeln("func1"); main.d(8): Error: template instance `main.profile_scope!"func1"` error instantiating ``` The underlying problem is that you can only alias expressions, i.e. you cannot use alias to generate macro like functionality. `measure("func1"); scope(exit) measure("func1");` is not an expression, it is simply a statement, so the alias cannot work. If you want to inject code directly at some place, basically your only option is to use a string mixin. I understand that you do not want to write `mixin` all the time, but to me, this does not look that bad: ``` auto profile_scope(string name) { import std.format : format; return q{import std.stdio : writeln; writeln("%1$s"); scope(exit) writeln("%1$s");}.format(name); } void main() { mixin(profile_scope("func1")); } ``` (replace writeln with your appropriate function call, "measure" in your example). |
March 07, 2019 Re: Aliasing a mixin (or alternative ways to profile a scope) | ||||
---|---|---|---|---|
| ||||
Posted in reply to Johannes Loher | On Thursday, 7 March 2019 at 20:34:48 UTC, Johannes Loher wrote:
> auto profile_scope(string name)
> {
> import std.format : format;
> return q{import std.stdio : writeln; writeln("%1$s"); scope(exit)
> writeln("%1$s");}.format(name);
> }
>
> void main()
> {
> mixin(profile_scope("func1"));
> }
Is there a way to achieve this while compiling with -betterC? I use a custom string struct right now, and your version needs TypeInfo, concatening using ~ needs the garbage collector. I have the feeling D is really not agreeing with the way I want to do things. If this is not possible, I will just roll with the Adam's struct solution.
|
March 07, 2019 Re: Aliasing a mixin (or alternative ways to profile a scope) | ||||
---|---|---|---|---|
| ||||
Posted in reply to Simon | Am 07.03.19 um 22:21 schrieb Simon:
>
> Is there a way to achieve this while compiling with -betterC? I use a custom string struct right now, and your version needs TypeInfo, concatening using ~ needs the garbage collector. I have the feeling D is really not agreeing with the way I want to do things. If this is not possible, I will just roll with the Adam's struct solution.
>
Using Adams struct solution is perfectly fine. I believe it is probably the cleaner solution overall.
My solution depends on TypeInfo because format does. I used format because it makes the string more readable. You can avoid this and use string concatenation in combination with providing the function name as template parameter instead:
```
enum profile_scope(string name) = "import core.stdc.stdio : printf;
printf(\""
~ name ~ "\n\"); scope(exit) printf(\"" ~ name ~ "\n\");";
extern (C) void main()
{
mixin(profile_scope!"func1");
}
```
This uses string concatenation only at compile time and not during run
time, so it does not require the garbage collector and is compatible
with betterC :)
|
March 07, 2019 Re: Aliasing a mixin (or alternative ways to profile a scope) | ||||
---|---|---|---|---|
| ||||
Posted in reply to Johannes Loher | Am 07.03.19 um 22:50 schrieb Johannes Loher:
> [...]
As a small addition, if you always want to pass the function name as a parameter, you can simplify this to the following:
```
enum profile_scope(string name = __FUNCTION__) = "import core.stdc.stdio
: printf; printf(\""
~ name ~ "\n\"); scope(exit) printf(\"" ~ name ~ "\n\");";
extern (C) void main()
{
mixin(profile_scope!());
foo();
}
extern (C) void foo() {
mixin(profile_scope!());
}
```
This will print
```
main.main
main.foo
main.foo
main.main
```
to the commandline.
|
March 08, 2019 Re: Aliasing a mixin (or alternative ways to profile a scope) | ||||
---|---|---|---|---|
| ||||
Posted in reply to Johannes Loher | On Thursday, 7 March 2019 at 21:50:17 UTC, Johannes Loher wrote:
> ```
> enum profile_scope(string name) = "import core.stdc.stdio : printf;
> printf(\""
> ~ name ~ "\n\"); scope(exit) printf(\"" ~ name ~ "\n\");";
>
> extern (C) void main()
> {
> mixin(profile_scope!"func1");
> }
>
> ```
> This uses string concatenation only at compile time and not during run
> time, so it does not require the garbage collector and is compatible
> with betterC :)
Thanks, this works flawlessly. Out of interest: what is the "enum" doing there? I had the exact same behaviour in a function before, that I only called at compile-time, so why did it complain then? Can I somehow tell the compiler that a function should only be available at compile-time?
|
March 09, 2019 Re: Aliasing a mixin (or alternative ways to profile a scope) | ||||
---|---|---|---|---|
| ||||
Posted in reply to Simon | On Friday, 8 March 2019 at 11:42:11 UTC, Simon wrote: > Thanks, this works flawlessly. Out of interest: what is the "enum" doing there? I had the exact same behaviour in a function before, that I only called at compile-time, so why did it complain then? Can I somehow tell the compiler that a function should only be available at compile-time? The enum (which in D is not only for enumerations, but also for "manifest constants") ensures it is evaluated at compile-time, since things are only evaluated at compile-time if they have to. See also Adam D. Ruppe's post in this thread: https://forum.dlang.org/post/blaawtdhljjantvgafud@forum.dlang.org |
March 10, 2019 Re: Aliasing a mixin (or alternative ways to profile a scope) | ||||
---|---|---|---|---|
| ||||
Posted in reply to Dennis | On Saturday, 9 March 2019 at 09:12:13 UTC, Dennis wrote:
> On Friday, 8 March 2019 at 11:42:11 UTC, Simon wrote:
>> Thanks, this works flawlessly. Out of interest: what is the "enum" doing there? I had the exact same behaviour in a function before, that I only called at compile-time, so why did it complain then? Can I somehow tell the compiler that a function should only be available at compile-time?
>
> The enum (which in D is not only for enumerations, but also for "manifest constants") ensures it is evaluated at compile-time, since things are only evaluated at compile-time if they have to.
> See also Adam D. Ruppe's post in this thread:
> https://forum.dlang.org/post/blaawtdhljjantvgafud@forum.dlang.org
Thanks!
|
Copyright © 1999-2021 by the D Language Foundation