DIP idea: q{}-inspired block mixins

Q. Schroll qs.il.paperinik at gmail.com
Wed Jun 10 23:51:45 UTC 2020


On Wednesday, 10 June 2020 at 04:03:46 UTC, mw wrote:
> I like it. Actually I was thinking about it since my previous 
> question and answer from Ali:
>
> https://forum.dlang.org/post/ravtsk$1uav$1@digitalmars.com
>
> The reason that template is so hard to be write tidily, is 
> because D does not have an easy way to stringfy a token.
>
> As a D beginner, I can come-up with this simple version:
> https://forum.dlang.org/post/cggmhdgmsxsutangohlf@forum.dlang.org
>
> --------------------
> 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);

Please don't do `string T`, typeName would be way better. 
Actually, my proposal doesn't improve that in length, but you 
could do

     // Assuming typeName and name in scope:
     mixin[typeName, name, _name = '_' ~ name]
     {
         private typeName _name;
         public typeName name() { return _name; }
         public ref name(return typeName value) { _name = value; 
return value; }
     }

In contrast to format() approaches, it at least can be readable.

At the points you're doing these:

> class Point {
>   mixin(RW!("int",     "x"));
>   mixin(RW!("double",  "y"));
>   mixin(RW!("string",  "z"));
> }

you'd need to copy the parts from above over and over. There's no 
(easy) way to make the stuff in the mixin[]{} a string literal 
that can be mixed in without resorting to, well, format() again. 
You could keep it to the []-list at least:

     enum RW(string typeName, string myname) = "
         mixin[tName = \"%s\", name = \"%s\", _name = \"_%s\"]
         {
             ...
         }
     ".format(typeName, myname, myname);

     mixin(RW!("int",     "x"));
     ...

I do think it's an improvement.

> Other people (esp. Ali) tried to work around this problem by 
> using template parameter T for type, and dispatch(name) to 
> stringfy that token. It is the only way to do it now in D, and 
> it took an D language expert (Ali, book author) quite sometime 
> to achieve this:
>
>   mixin RW!int.x;    // <-- NICE :)
>
> in his second attempt. And even he said it's "convoluted".
>
> The language shouldn't be made it so hard to achieve something 
> this simple, e.g. a novice C++ programmer can write this 
> equivalent thing without too much effort:
>
> -----------------------------
> #define ATTR_NAME(name)  _##name
>
> #define READER(type, name)      \
> public:    type name () const {return ATTR_NAME(name);}
>
> #define WRITER(type, name)      \
> public:  void name(type val)  {ATTR_NAME(name) = val;}
>
> #define READ_ONLY_ATTR(type, name)      \
> protected: type ATTR_NAME(name);        \
>            READER(type, name)
>
> #define DECL_ATTR(type, name)   \
>    READ_ONLY_ATTR(type, name)   \
>            WRITER(type, name)
>
> class Point {
>   DECL_ATTR(int, x);
>   DECL_ATTR(int, y);
>   DECL_ATTR(int, z);
> };
> -----------------------------
>
> And do you think this simple C++ macro version is much more 
> easily readable & maintainable than the D expert's version?

I think the C++ macro does a good job here. Macros are not evil, 
just easy to misuse. C++-Macros have a ton of issues, but the 
mere idea of token-based replacement is not bad at all.

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

I like that approach, too. So much better than the above! Yes, 
here, in the opDispatch, my proposal wouldn't shorten anything 
(it would never do this), but make it much more readable.

> In short, we have the mechanism already (thru opDispatch(...)), 
> but please export it as first class D citizen.
>
> I'm glad you made this proposal, and I hope it will be adopted.

I'd also hope it flies.


More information about the Digitalmars-d mailing list