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

Reply via email to