Re: how to achieve C's Token Pasting (##) Operator to generate variable name in D?

2020-06-04 Thread mw via Digitalmars-d-learn

On Thursday, 4 June 2020 at 19:42:57 UTC, mw wrote:

On Thursday, 4 June 2020 at 18:42:05 UTC, H. S. Teoh wrote:
TBH, whenever I run into a diamond inheritance problem or 
similar, my first reaction is, I'm using the wrong tool for

   ^^

Haha, it's also because most of the populate OO languages didn't 
solve the diamond problem, and made the multiple inheritance hard 
to use in such situation, that's how the programmers learnt this 
"first reaction" from past bad experience.


Conversely, if all the OO languages solved the diamond problem 
cleanly from the very start, the programmers will never learn 
such reaction.




Re: how to achieve C's Token Pasting (##) Operator to generate variable name in D?

2020-06-04 Thread mw via Digitalmars-d-learn

On Thursday, 4 June 2020 at 18:42:05 UTC, H. S. Teoh wrote:
TBH, whenever I run into a diamond inheritance problem or 
similar, my first reaction is, I'm using the wrong tool for 
modelling my data; I should be using some kind of 
component-based system instead of OO inheritance.


I have no problem with whatever modelling technique the 
programmer want to choose.


What I hate to see is: if a language does provide the OO 
mechanism, but having some loop-holes that causes trouble for the 
programmer who choose to use it. Esp. when these loop-holes are 
crept in after the language's initial design.


(For example, I won't discuss multiple inheritance on a C forum, 
it's not that language designed for.)




Re: how to achieve C's Token Pasting (##) Operator to generate variable name in D?

2020-06-04 Thread H. S. Teoh via Digitalmars-d-learn
On Thu, Jun 04, 2020 at 06:09:35PM +, mw via Digitalmars-d-learn wrote:
[...]
> --
> class Person : NameI, AddrI {
>   mixin NameT!Person rename equals as name_equals;
>   mixin AddrT!Person rename equals as addr_equals;
> 
>   bool equals(Person other) {
> return this.name_equals(other) &&
>this.addr_equlas(other);
>   }
> }
> --

TBH, whenever I run into a diamond inheritance problem or similar, my
first reaction is, I'm using the wrong tool for modelling my data; I
should be using some kind of component-based system instead of OO
inheritance.

Nowadays I rarely use OO-style inheritance for data modelling anymore;
it's still useful for rare cases where a straight hierarchy makes sense
(traditional GUI widgets, for example, or parse trees), but for complex
modelling I just stop pretending that there's a direct mapping from
problem domain to language constructs, and instead build containers that
have arbitrary component combinations as an infrastructure instead.

Recently I've been dabbling in ECS (entity-component-system) adaptations
from gamedev: the system part is not useful to me, but the idea behind
entity-component storage is very useful for modelling complex data, much
more suitable than traditional OO inheritance IMO.


T

-- 
I am Ohm of Borg. Resistance is voltage over current.


Re: how to achieve C's Token Pasting (##) Operator to generate variable name in D?

2020-06-04 Thread mw via Digitalmars-d-learn

On Sunday, 31 May 2020 at 06:28:11 UTC, mw wrote:

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?



This is related to D's silent crept-in multiple inheritance 
problem, a solution via language improvement is here:


https://forum.dlang.org/post/lsnhqdoyatkzbzqbs...@forum.dlang.org


I'd imagine something like this:

--
class Person : NameI, AddrI {
  mixin NameT!Person rename equals as name_equals;
  mixin AddrT!Person rename equals as addr_equals;

  bool equals(Person other) {
return this.name_equals(other) &&
   this.addr_equlas(other);
  }
}
--



Re: how to achieve C's Token Pasting (##) Operator to generate variable name in D?

2020-05-31 Thread Ali Çehreli via Digitalmars-d-learn
On 5/31/20 1:00 PM, mw wrote:> On Sunday, 31 May 2020 at 09:37:24 UTC, 
Ali Çehreli wrote:


> One question: in Sebastiaan's solution opDispatch is performed at
> run-time

Templates don't exist at run time. They are used for generating code at 
compile time and that's it.


opDispatch is a template. Like all templates, it's evaluated at compile 
time and code is generated for it at compile time. However, if 
opDispatch() is a member function template, then there will be a 
function call execution at runtime but this is not different from any 
other member function call.


Here is a struct with an opDispatch() used as a member function template.

struct XmlElement {
  static opDispatch(string tag)(string value) {
import std.range;
import std.format;

enum opening = format!"<%s>"(tag);
enum closing = format!""(tag);

// Note: Although we return a chained range, this could return a
// string[3] as well, which may possibly be more performant.
return chain(opening, value, closing);
  }
}

import std.stdio;

void main() {
  writeln(XmlElement.foo("hello"));
  writeln(XmlElement.bar("world"));
}

opDispatch() is instantiated with two strings in the program: "foo" and 
"bar". As a result, the XmlElement struct will be the equivalent of the 
following one:


struct XmlElement {
  static foo(string value) {
enum opening = "";
enum closing = "";
return chain(opening, value, closing);
  }

  static bar(string value) {
enum opening = "";
enum closing = "";
return chain(opening, value, closing);
  }
}

Note how two member functions are added to XmlElement and all of the 
'opening' and 'closing' strings are computed at compile time.


In my solution opDispatch() boils down to a "mixin template" itself. As 
Paul Backus's code does, that mixin template is used for adding the 
following members to the struct for each instantiation of opDispatch(). 
For example, for x, the struct will gain the following template 
definition. (_FOR_X is my annotation).


mixin template opDispatch_FOR_X(alias code = codeImpl()) {
private int _x;
public auto x() { return _x; }
public auto x(T val) { _x = val; return this; }
}

Note that each instance of opDispatch() for "x", "y", etc. will gain a 
template definition. Those definitions are a compile-time cost. 
Eventually, when user code mixes-in the corresponding template, then the 
three member above will be added to the user's struct.


After that, there is no run-time cost more than adding those members by 
hand.


Ali




Re: how to achieve C's Token Pasting (##) Operator to generate variable name in D?

2020-05-31 Thread mw via Digitalmars-d-learn

On Sunday, 31 May 2020 at 09:37:24 UTC, Ali Çehreli wrote:

On 5/31/20 2:26 AM, Ali Çehreli wrote:

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



Thank you all for the refinement.

One question: in Sebastiaan's solution opDispatch is performed at 
run-time, how efficient is the D runtime's implementation of 
opDispatch compared with a direct regular method call (or a 
virtual method call in general):

```
  public  final  int  x()  {return _x;}  // in this example 
it can be final

```

In short, while I want to reduce the boilerplate code I have to 
write, I don't want to pay any extra run-time cost; compile-time 
cost is fine.



@Ali in your solution, opDispatch is also performed at run-time 
instead of compile-time (I'm not sure)? since it's inside struct 
RW, (each x, y is actually a struct inside Point)?





Re: how to achieve C's Token Pasting (##) Operator to generate variable name in D?

2020-05-31 Thread Ali Çehreli via Digitalmars-d-learn

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



Re: how to achieve C's Token Pasting (##) Operator to generate variable name in D?

2020-05-31 Thread Ali Çehreli via Digitalmars-d-learn

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



Re: how to achieve C's Token Pasting (##) Operator to generate variable name in D?

2020-05-31 Thread Sebastiaan Koppe via Digitalmars-d-learn

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);
}
```


Re: how to achieve C's Token Pasting (##) Operator to generate variable name in D?

2020-05-31 Thread mw via Digitalmars-d-learn

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?



Re: how to achieve C's Token Pasting (##) Operator to generate variable name in D?

2020-05-30 Thread Paul Backus via Digitalmars-d-learn

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;
  publicint  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


Re: how to achieve C's Token Pasting (##) Operator to generate variable name in D?

2020-05-30 Thread Johannes Loher via Digitalmars-d-learn

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)
}



Re: how to achieve C's Token Pasting (##) Operator to generate variable name in D?

2020-05-30 Thread mw via Digitalmars-d-learn

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;
  publicint  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("\x0aprivate %1$s 
_%2$s;\x0apublic  %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.



Re: how to achieve C's Token Pasting (##) Operator to generate variable name in D?

2020-05-30 Thread kinke via Digitalmars-d-learn

Using a mixin:

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

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



Re: how to achieve C's Token Pasting (##) Operator to generate variable name in D?

2020-05-30 Thread Paul Backus via Digitalmars-d-learn

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


how to achieve C's Token Pasting (##) Operator to generate variable name in D?

2020-05-30 Thread mw via Digitalmars-d-learn
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.