Thread overview | ||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
May 30, 2020 how to achieve C's Token Pasting (##) Operator to generate variable name in D? | ||||
---|---|---|---|---|
| ||||
I want to generate a new symbol (new variable name) from existing one: e.g. in C: $ cat t.c -------------------------------------------- #define f(x) _##x int main() { int f(x) = 3; return _x; } $ make t cc t.c -o t $ ./t $ echo $? 3 -------------------------------------------- I wonder how to do this in D? using template / mixin? traits? Can you show me an example? Thanks. |
May 30, 2020 Re: how to achieve C's Token Pasting (##) Operator to generate variable name in D? | ||||
---|---|---|---|---|
| ||||
Posted in reply to mw | Using a mixin: string f(string x) { return "_" ~ x; } int main() { mixin("int "~f("x")~" = 3;"); return _x; } |
May 30, 2020 Re: how to achieve C's Token Pasting (##) Operator to generate variable name in D? | ||||
---|---|---|---|---|
| ||||
Posted in reply to mw | On Saturday, 30 May 2020 at 22:06:30 UTC, mw wrote: > I want to generate a new symbol (new variable name) from existing one: e.g. in C: > > > $ cat t.c > -------------------------------------------- > #define f(x) _##x > > int main() { > int f(x) = 3; > return _x; > } > > $ make t > cc t.c -o t > $ ./t > $ echo $? > 3 > -------------------------------------------- > > I wonder how to do this in D? using template / mixin? traits? > > Can you show me an example? > > Thanks. enum f(string x) = "_" ~ x; int main() { mixin("int ", f!"x", " = 3;"); return _x; } This uses a templated [1] manifest constant [2] to generate the variable name at compile time, and a mixin statement [3] to insert the definition of `_x` into the program. [1] https://dlang.org/spec/template.html#variable-template [2] https://dlang.org/spec/enum.html#manifest_constants [3] https://dlang.org/spec/statement.html#mixin-statement |
May 30, 2020 Re: how to achieve C's Token Pasting (##) Operator to generate variable name in D? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Paul Backus | On Saturday, 30 May 2020 at 22:21:14 UTC, Paul Backus wrote: > enum f(string x) = "_" ~ x; > > int main() { > mixin("int ", f!"x", " = 3;"); > return _x; > } > > This uses a templated [1] manifest constant [2] to generate the variable name at compile time, and a mixin statement [3] to insert the definition of `_x` into the program. > > [1] https://dlang.org/spec/template.html#variable-template > [2] https://dlang.org/spec/enum.html#manifest_constants > [3] https://dlang.org/spec/statement.html#mixin-statement Thank you all for the reply. I hate to write boilerplate code: class Point { private int _x; public int x() {return _x;} public Point x(int v) {_x=v; return this;} ... // ... y, z } this is what I've got: $ cat b.d -------------------------------------------------------------------------------- // dmd -unittest -vcg-ast -c b.d import std.format; enum RW(string T, string name) = format(q{ private %1$s _%2$s; public %1$s %2$s() {return _%2$s;} public auto %2$s(%1$s v) {_%2$s = v; return this;} }, T, name); class Point { mixin(RW!("int", "x")); mixin(RW!("double", "y")); mixin(RW!("string", "z")); } $ dmd -unittest -vcg-ast -c b.d $ head -n 24 b.d.cg import object; import std.format; enum RW(string T, string name) = format("\x0a private %1$s _%2$s;\x0a public %1$s %2$s() {return _%2$s;}\x0a public auto %2$s(%1$s v) {_%2$s = v; return this;}\x0a ", T, name); class Point : Object { mixin(RW!("int", "x") { enum string RW = ['\x0a', ' ', ' ', ' ', ' ', 'p', 'r', 'i', 'v', 'a', 't', 'e', ' ', 'i', 'n', 't', ' ', '_', 'x', ';', '\x0a', ' ', ' ', ' ', ' ', 'p', 'u', 'b', 'l', 'i', 'c', ' ', ' ', 'i', 'n', 't', ' ', ' ', 'x', '(', ')', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '{', 'r', 'e', 't', 'u', 'r', 'n', ' ', '_', 'x', ';', '}', '\x0a', ' ', ' ', ' ', ' ', 'p', 'u', 'b', 'l', 'i', 'c', ' ', ' ', 'a', 'u', 't', 'o', ' ', ' ', 'x', '(', 'i', 'n', 't', ' ', 'v', ')', ' ', ' ', '{', '_', 'x', ' ', '=', ' ', 'v', ';', ' ', ' ', 'r', 'e', 't', 'u', 'r', 'n', ' ', 't', 'h', 'i', 's', ';', '}', '\x0a', ' ', ' ']; } ); mixin(RW!("double", "y") { enum string RW = ['\x0a', ' ', ' ', ' ', ' ', 'p', 'r', 'i', 'v', 'a', 't', 'e', ' ', 'd', 'o', 'u', 'b', 'l', 'e', ' ', '_', 'y', ';', '\x0a', ' ', ' ', ' ', ' ', 'p', 'u', 'b', 'l', 'i', 'c', ' ', ' ', 'd', 'o', 'u', 'b', 'l', 'e', ' ', ' ', 'y', '(', ')', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '{', 'r', 'e', 't', 'u', 'r', 'n', ' ', '_', 'y', ';', '}', '\x0a', ' ', ' ', ' ', ' ', 'p', 'u', 'b', 'l', 'i', 'c', ' ', ' ', 'a', 'u', 't', 'o', ' ', ' ', 'y', '(', 'd', 'o', 'u', 'b', 'l', 'e', ' ', 'v', ')', ' ', ' ', '{', '_', 'y', ' ', '=', ' ', 'v', ';', ' ', ' ', 'r', 'e', 't', 'u', 'r', 'n', ' ', 't', 'h', 'i', 's', ';', '}', '\x0a', ' ', ' ']; } ); mixin(RW!("string", "z") { enum string RW = ['\x0a', ' ', ' ', ' ', ' ', 'p', 'r', 'i', 'v', 'a', 't', 'e', ' ', 's', 't', 'r', 'i', 'n', 'g', ' ', '_', 'z', ';', '\x0a', ' ', ' ', ' ', ' ', 'p', 'u', 'b', 'l', 'i', 'c', ' ', ' ', 's', 't', 'r', 'i', 'n', 'g', ' ', ' ', 'z', '(', ')', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '{', 'r', 'e', 't', 'u', 'r', 'n', ' ', '_', 'z', ';', '}', '\x0a', ' ', ' ', ' ', ' ', 'p', 'u', 'b', 'l', 'i', 'c', ' ', ' ', 'a', 'u', 't', 'o', ' ', ' ', 'z', '(', 's', 't', 'r', 'i', 'n', 'g', ' ', 'v', ')', ' ', ' ', '{', '_', 'z', ' ', '=', ' ', 'v', ';', ' ', ' ', 'r', 'e', 't', 'u', 'r', 'n', ' ', 't', 'h', 'i', 's', ';', '}', '\x0a', ' ', ' ']; } ); } -------------------------------------------------------------------------------- Am I doing the right thing in D? any improvement you'd suggest? e.g. I don't quite like have to put the type and var name in the quotes as string: mixin(RW!("int", "x")); Is there a better way to achieve this? esp. for the type `int`, is there any way I don't have to quote it as string? Thanks. |
May 31, 2020 Re: how to achieve C's Token Pasting (##) Operator to generate variable name in D? | ||||
---|---|---|---|---|
| ||||
Posted in reply to mw | On Saturday, 30 May 2020 at 23:39:31 UTC, mw wrote:
> On Saturday, 30 May 2020 at 22:21:14 UTC, Paul Backus wrote:
>> [...]
>
>
> Thank you all for the reply.
>
> I hate to write boilerplate code:
>
> [...]
import std.stdio : writeln;
mixin template f(T, string name, T value = T.init)
{
mixin("T _" ~ name ~ " = value;");
}
void main()
{
mixin f!(int, "x", 3);
_x.writeln; // prints 3
mixin f!(float, "y", 1.23f);
_y.writeln; // prints 1.23
mixin f!(string, "z");
_z.writeln; // prints an empty string (== string.init)
}
|
May 31, 2020 Re: how to achieve C's Token Pasting (##) Operator to generate variable name in D? | ||||
---|---|---|---|---|
| ||||
Posted in reply to mw | On Saturday, 30 May 2020 at 23:39:31 UTC, mw wrote: > > Thank you all for the reply. > > I hate to write boilerplate code: > > class Point { > private int _x; > public int x() {return _x;} > public Point x(int v) {_x=v; return this;} > > ... > // ... y, z > } > > > this is what I've got: > $ cat b.d > -------------------------------------------------------------------------------- > // dmd -unittest -vcg-ast -c b.d > import std.format; > > > enum RW(string T, string name) = > format(q{ > private %1$s _%2$s; > public %1$s %2$s() {return _%2$s;} > public auto %2$s(%1$s v) {_%2$s = v; return this;} > }, T, name); > > > class Point { > mixin(RW!("int", "x")); > mixin(RW!("double", "y")); > mixin(RW!("string", "z")); > } [...] > Is there a better way to achieve this? esp. for the type `int`, is there any way I don't have to quote it as string? > > Thanks. You can simplify this considerably using a mixin template [1]: --- mixin template RW(T, string name) { private T var; public T get() { return var; } public typeof(this) set(T val) { var = val; return this; } mixin("private alias _", name, " = var;"); // two aliases with the same name create an overload set mixin("public alias ", name, " = get;"); mixin("public alias ", name, " = set;"); } class Point { mixin RW!(int, "x"); mixin RW!(int, "y"); // etc. } --- You still need string mixins to make the names work, but the rest can be done without them. Large string mixins tend to be error-prone and difficult to debug, so it's usually a good idea to make them as small as you reasonably can [2]. [1] https://dlang.org/spec/template-mixin.html [2] http://www.arsdnet.net/this-week-in-d/2016-feb-21.html |
May 31, 2020 Re: how to achieve C's Token Pasting (##) Operator to generate variable name in D? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Paul Backus | On Sunday, 31 May 2020 at 00:46:09 UTC, Paul Backus wrote: > You can simplify this considerably using a mixin template [1]: > > --- > mixin template RW(T, string name) { > private T var; > public T get() { return var; } > public typeof(this) set(T val) { var = val; return this; } > > mixin("private alias _", name, " = var;"); > // two aliases with the same name create an overload set > mixin("public alias ", name, " = get;"); > mixin("public alias ", name, " = set;"); > } > > class Point { > mixin RW!(int, "x"); > mixin RW!(int, "y"); mixin RW!(string, "z"); // add > } > --- This is better, ... but it breaks std.traits: void main() { auto fields = FieldNameTuple!(Point); writeln(fields); } $ ./b varvarvar And normally, we cannot define 2 fields with different types: class P { int x; double x; // b.d(45): Error: variable b.P.x conflicts with variable b.P.x at b.d(44) } With the above template we somehow tricked the compiler to be able to do this? Is this a loop-hole we should file a bug? |
May 31, 2020 Re: how to achieve C's Token Pasting (##) Operator to generate variable name in D? | ||||
---|---|---|---|---|
| ||||
Posted in reply to mw | On 5/30/20 11:28 PM, mw wrote: > On Sunday, 31 May 2020 at 00:46:09 UTC, Paul Backus wrote: >> You can simplify this considerably using a mixin template [1]: >> >> --- >> mixin template RW(T, string name) { >> private T var; >> public T get() { return var; } >> public typeof(this) set(T val) { var = val; return this; } >> >> mixin("private alias _", name, " = var;"); >> // two aliases with the same name create an overload set >> mixin("public alias ", name, " = get;"); >> mixin("public alias ", name, " = set;"); >> } >> >> class Point { >> mixin RW!(int, "x"); >> mixin RW!(int, "y"); > > mixin RW!(string, "z"); // add > >> } >> --- > > This is better, ... but it breaks std.traits: The following code solves that I think the following syntax is an improvement over Paul Backus's solution because it allows .x instead of "x" by taking advantage of a static opDispatch. But it requires parenthesis because now it's a string mixin, which is likely to be noticeably slow to compile too. struct RW(T) { static string opDispatch(string name)() { import std.format; return format!q{ private %s _%s; public auto %s() { return _%s; } public auto %s(%s val) { _%s = val; return this; } }(T.stringof, name, name, name, name, T.stringof, name); } } struct Point { mixin (RW!int.x); mixin (RW!int.y); // etc. } import std.traits; import std.stdio; void main() { pragma(msg, FieldNameTuple!(Point)); auto p = Point(1, 2); p.x = 42; p.y = 43; writeln(p); } The spec allows opDispatch to be an eponymous template: https://dlang.org/spec/operatoroverloading.html#dispatch Unfortunately, I could not reach the following cleaner syntax with a mixin template: mixin RW!int.x; Ali |
May 31, 2020 Re: how to achieve C's Token Pasting (##) Operator to generate variable name in D? | ||||
---|---|---|---|---|
| ||||
Posted in reply to mw | On Saturday, 30 May 2020 at 23:39:31 UTC, mw wrote:
> Am I doing the right thing in D? any improvement you'd suggest?
>
> e.g. I don't quite like have to put the type and var name in the quotes as string:
>
> mixin(RW!("int", "x"));
>
> Is there a better way to achieve this? esp. for the type `int`, is there any way I don't have to quote it as string?
>
> Thanks.
This would also be an option.
```
import std;
class Point {
struct Inner {
int x;
double y;
}
private Inner inner;
Point opDispatch(string name, T)(T value) {
mixin("inner."~name~" = value;");
return this;
}
auto opDispatch(string name)() {
mixin("return inner."~name~";");
}
}
void main()
{
Point b = new Point();
b.x(4).y(5.0);
writeln(b.x);
}
```
|
May 31, 2020 Re: how to achieve C's Token Pasting (##) Operator to generate variable name in D? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Ali Çehreli | On 5/31/20 2:26 AM, Ali Çehreli wrote:
> Unfortunately, I could not reach the following cleaner syntax with a mixin template:
>
> mixin RW!int.x;
Ok, I solved that too with a very convoluted "eponymous mixin template opDispatch." :)
struct RW(T) {
template opDispatch(string name) {
static codeImpl() {
import std.format;
return format!q{
private %s _%s;
public auto %s() { return _%s; }
public auto %s(%s val) { _%s = val; return this; }
}(T.stringof, name,
name, name,
name, T.stringof, name);
}
mixin template opDispatch(alias code = codeImpl()) {
mixin (code);
}
}
}
struct Point {
mixin RW!int.x; // <-- NICE :)
mixin RW!int.y;
// etc.
}
import std.traits;
import std.stdio;
void main() {
pragma(msg, FieldNameTuple!(Point));
auto p = Point(1, 2);
p.x = 42;
p.y = 43;
writeln(p);
}
Ali
|
Copyright © 1999-2021 by the D Language Foundation