September 14, 2020 Re: reflection based on my experience so far on compile-time meta-programming in D as a novice user: the problems | ||||
---|---|---|---|---|
| ||||
Posted in reply to Sebastiaan Koppe | On Monday, 14 September 2020 at 12:32:35 UTC, Sebastiaan Koppe wrote:
>
> The implied restriction was that the generate function takes a type as its template argument, and then generates a string containing a valid D statement with said type.
>
> But fear not:
>
> ----
>
> string generate(string typeName)() {
> return "%s bla;".format(typeName);
> }
>
> void bla(T)() {
> mixin(generate!(T.stringof));
> bla = 5;
> }
There's no guarantee that `T.stringof` produces a name that's valid in the scope where you're mixing it in:
import somelib: Y = X;
alias blaY = bla!Y;
// Error: undefined identifier `X`
In general, it's impossible to round-trip a type through a string. The closest thing is .mangleof, which is guaranteed to produce a globally-unique result, but can't be converted back into a type afterward. So maybe what you actually want is `__traits(demangle)`?
|
September 14, 2020 Re: reflection based on my experience so far on compile-time meta-programming in D as a novice user: the problems | ||||
---|---|---|---|---|
| ||||
Posted in reply to Sebastiaan Koppe | On Monday, 14 September 2020 at 12:32:35 UTC, Sebastiaan Koppe wrote:
> On Monday, 14 September 2020 at 10:54:07 UTC, Paul Backus wrote:
>> Don't overthink it:
>>
>> string generate(string typeName)() {
>> return "%s bla;".format(typeName);
>> }
>>
>> void main() {
>> mixin(generate!"int");
>> bla = 5;
>> }
>
> The implied restriction was that the generate function takes a type as its template argument, and then generates a string containing a valid D statement with said type.
>
> But fear not:
>
> ----
>
> string generate(string typeName)() {
> return "%s bla;".format(typeName);
> }
>
> void bla(T)() {
> mixin(generate!(T.stringof));
> bla = 5;
> }
You mean:
mixin(generate!"T").
"token" :)
|
September 14, 2020 Re: reflection based on my experience so far on compile-time meta-programming in D as a novice user: the problems | ||||
---|---|---|---|---|
| ||||
Posted in reply to FeepingCreature | On Monday, 14 September 2020 at 15:38:07 UTC, FeepingCreature wrote:
> You mean:
>
> mixin(generate!"T").
>
> "token" :)
You are mixin-in the T right inside the template, where T is defined. That is not always the case though.
----
struct S {
mixin(generate!int);
}
string generate(T)() {
// [...] bunch of introspect code
return "T blah;"; // no works
}
---
but by introducing an intermediate layer it works:
---
struct S {
mixin generate!int;
}
mixin template generate(T) {
mixin(generateImpl!T);
}
string generateImpl(T)() {
// [...] bunch of introspect code
return "T blah;";
}
---
So yeah, it can work without stringof. But is it any better? I don't think so.
|
September 14, 2020 Re: reflection based on my experience so far on compile-time meta-programming in D as a novice user: the problems | ||||
---|---|---|---|---|
| ||||
Posted in reply to Sebastiaan Koppe | On Monday, 14 September 2020 at 09:14:42 UTC, Sebastiaan Koppe wrote:
>
> I have been trying, but there is one I can't get...
>
> ---
>
> import std;
>
> string generate(T)() {
> return "%s bla;".format(T.stringof);
> }
>
> void main() {
> mixin(generate!int);
> bla = 5;
> }
Thanks for the simple example to illustrate my points:
-- in D, there are too many choices, with no clear guideline which one is *THE* one to use for a particular purpose
-- in D, there is no easy way to convert between token <==> string.
from the following discussions of this example, it clearly shows people have different choices to pass either the token <int>, or string "int", and use ".stringof" or ".mangleof", some leads to dead end, some cause scope errors.
(And Sebastiaan is a long timer on this forum than me, yet still puzzled to make this simple meta-programming example to work.)
|
September 14, 2020 Re: reflection based on my experience so far on compile-time meta-programming in D as a novice user: the problems | ||||
---|---|---|---|---|
| ||||
Posted in reply to mw | On Sunday, 13 September 2020 at 18:32:17 UTC, mw wrote: >>> https://github.com/mingwugmail/talibd >>> >>> I end up using C macro to generate D functions, the single template is this one: >>> >>> https://github.com/mingwugmail/talibd/blob/master/source/talibd.h#L117 >>> #define DECL_TA_FUNC(TA_FUNC, FUNC_INS, FUNC_OUTS, expected_lookback) __NL__\ >> >> The most straightforward way to do this in D is with a mixin template. Something like: >> >> mixin template DECL_TA_FUNC(string TA_FUNC, FUNC_INS, FUNC_OUTS, int expected_lookback) >> { >> bool impl(...) >> { >> // ... >> } Actually I just realized, that Paul literally means `impl(...)`, I have thought `(...)` it's an abbreviation for illustration purpose. The reason is that it's not easy (or not possible at all! to pass two or more sets of variadic parameters[1] to a function in D for meta-programming. Well, here Paul give a nice trick to pass them (FUNC_INS, and FUNC_OUTS) as template parameters. However, if we take a look of the C-macro generated function signature: https://github.com/mingwugmail/talibd/blob/master/source/talib_func.d#L103 bool TA_MACD(double[] inData , // the following 3 is FUNC_OUTS double[] outMACD, double[] outMACDSignal, double[] outMACDHist , // the following 3 is FUNC_INS int optInFastPeriod=default_optInFastPeriod, int optInSlowPeriod=default_optInSlowPeriod, int optInSignalPeriod=default_optInSignalPeriod) { ... } I would naturally think this is the most straight-forward target function signature I want to generate. And I can do it without any trouble at all with C-macro. https://github.com/mingwugmail/talibd/blob/master/source/talib_func.h#L118 But if we compare it with Paul's D solution siganature: bool impl(...) // literally `(...)` here! That's the difficulty I have experienced. The natural most straight-forward target function signature (that I have in mind when I start to program) have become a convoluted work-around in D. That's why I cannot figure out how to do it. Now even with all the suggestions of using `-vcg-ast` or `pragma(msg, X.stringof)` debug utilities to help, the mental burden from the most straight-forward targeted function signature to the actual D-generated function signature is still far away! Further more, if when people use such generated function, at the call-site: e.g. https://github.com/mingwugmail/talibd/blob/master/source/oo.d#L47 return TA_MACD(_prices, macd, macdSignal, macdHist); If something goes wrong, and the user want to go back and check the function definition: -- C-macro generated as I showed above, v.s -- D version: bool impl(...) // literally `(...)` here! or, even with the `-vcg-ast` or `pragma(msg ...)` output You tell me which one is more clear & helpful to identify the problem! So here is my point (4) on the problems of D meta-programming: -- because of the points (1~3), the resulting D meta-programming version is often convoluted, and the code may have very bigger distance from the most straight-forward targeted function signature one have in mind from the beginning. And this makes writing & (and more importantly) reading (by a non-code-author) such code difficult. [1] https://forum.dlang.org/post/sjkbrycitdsgtyxcpxdj@forum.dlang.org |
September 14, 2020 Re: reflection based on my experience so far on compile-time meta-programming in D as a novice user: the problems | ||||
---|---|---|---|---|
| ||||
Posted in reply to mw | On 9/14/20 1:40 PM, mw wrote:
> -- because of the points (1~3), the resulting D meta-programming version is often convoluted, and the code may have very bigger distance from the most straight-forward targeted function signature one have in mind from the beginning. And this makes writing & (and more importantly) reading (by a non-code-author) such code difficult.
>
>
You're looking at C macros, which D specifically does not do, mostly because of the crap that can come out of them (note you can use dpp if you really want them).
Your C macro I think translates pretty easily to a D mixin, because it's generating a complete function:
string DECL_TA_FUNC(string TA_FUNC, string[] FUNC_INS, string[] FUNC_OUTS)
{
// this would be easier with string interpolation!
return format(q{
bool %s(double[] inData, %-(double[] %s,%), %-(%s,%)) {
%(assert %s.length == inData.length;%)
int begin, num;
int lookback = %s_Lookback( %(%s... you get the idea
}}, TA_FUNC, FUNC_OUTS, FUNC_INS, FUNC_OUTS, TA_FUNC, ...);
}
enum MA_INS = [
"int MA_optInTimePeriod",
"int TA_MAType optInMAType"
];
enum MA_OUTS = [
"outMA"
];
mixin(DECL_TA_FUNC(TA_MA, MA_INS, MA_OUTS, somethingElse, whatever));
I didn't feel like translating that whole file. I think you can do it with probably 25% of the size of that C macro code, and IMO much more readable. No idea why you would prefer C preprocessor, D has far superior string manipulation capabilities.
-Steve
|
September 14, 2020 Re: reflection based on my experience so far on compile-time meta-programming in D as a novice user: the problems | ||||
---|---|---|---|---|
| ||||
Posted in reply to Steven Schveighoffer | On Monday, 14 September 2020 at 18:20:02 UTC, Steven Schveighoffer wrote:
> // this would be easier with string interpolation!
> , D has far superior string manipulation capabilities.
Basically, your solution is: let's just use strings! (forget about of all the other fancy mechanism I've listed in point (1)). Yes, that's right: source code should just be strings.
From that point of view, C-preprocessor is conceptually at a high level.
|
September 14, 2020 Re: reflection based on my experience so far on compile-time meta-programming in D as a novice user: the problems | ||||
---|---|---|---|---|
| ||||
Posted in reply to Steven Schveighoffer | On Mon, Sep 14, 2020 at 02:20:02PM -0400, Steven Schveighoffer via Digitalmars-d wrote: [...] > You're looking at C macros, which D specifically does not do, mostly because of the crap that can come out of them (note you can use dpp if you really want them). [...] Yep: https://www.ioccc.org/2005/anon/anon.c ;-) T -- To provoke is to call someone stupid; to argue is to call each other stupid. |
September 14, 2020 Re: reflection based on my experience so far on compile-time meta-programming in D as a novice user: the problems | ||||
---|---|---|---|---|
| ||||
Posted in reply to H. S. Teoh | On Monday, 14 September 2020 at 18:36:53 UTC, H. S. Teoh wrote:
>
> Yep: https://www.ioccc.org/2005/anon/anon.c
As I said, I'm using the *generated* code:
cpp -P foo.h > foo.c // <- this generated code
For a fair comparison, how Steven's *generating* code is more superior to read than anon.c?
```
string DECL_TA_FUNC(string TA_FUNC, string[] FUNC_INS, string[] FUNC_OUTS)
{
// this would be easier with string interpolation!
return format(q{
bool %s(double[] inData, %-(double[] %s,%), %-(%s,%)) {
%(assert %s.length == inData.length;%)
int begin, num;
int lookback = %s_Lookback( %(%s... you get the idea
}}, TA_FUNC, FUNC_OUTS, FUNC_INS, FUNC_OUTS, TA_FUNC, ...);
}
enum MA_INS = [
"int MA_optInTimePeriod",
"int TA_MAType optInMAType"
];
enum MA_OUTS = [
"outMA"
];
mixin(DECL_TA_FUNC(TA_MA, MA_INS, MA_OUTS, somethingElse, whatever));
```
|
September 14, 2020 Re: reflection based on my experience so far on compile-time meta-programming in D as a novice user: the problems | ||||
---|---|---|---|---|
| ||||
Posted in reply to mw | On Monday, 14 September 2020 at 18:30:16 UTC, mw wrote:
> On Monday, 14 September 2020 at 18:20:02 UTC, Steven Schveighoffer wrote:
>> // this would be easier with string interpolation!
>> , D has far superior string manipulation capabilities.
>
> Basically, your solution is: let's just use strings! (forget about of all the other fancy mechanism I've listed in point (1)).
> Yes, that's right: source code should just be strings.
>
> From that point of view, C-preprocessor is conceptually at a high level.
This is hilariously backwards. The c preprocessor is literally just pasting strings around.
-Steve
|
Copyright © 1999-2021 by the D Language Foundation