Jump to page: 1 2
Thread overview
how to achieve C's Token Pasting (##) Operator to generate variable name in D?
May 30, 2020
mw
May 30, 2020
kinke
May 30, 2020
Paul Backus
May 30, 2020
mw
May 31, 2020
Johannes Loher
May 31, 2020
Paul Backus
May 31, 2020
mw
May 31, 2020
Ali Çehreli
May 31, 2020
Ali Çehreli
May 31, 2020
mw
May 31, 2020
Ali Çehreli
Jun 04, 2020
mw
Jun 04, 2020
H. S. Teoh
Jun 04, 2020
mw
Jun 04, 2020
mw
May 31, 2020
Sebastiaan Koppe
May 30, 2020
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
Using a mixin:

string f(string x) { return "_" ~ x; }

int main() {
  mixin("int "~f("x")~" = 3;");
  return _x;
}

May 30, 2020
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
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
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
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
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
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
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
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

« First   ‹ Prev
1 2