www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - mixin identifiers concept

reply mesni <mensikovk817 gmail.com> writes:
```d
static foreach(name; ["boo", "foo"]){
     string file_#name = readText(name~".txt");
     string file_#name

}

writeln(file_boo);
writeln(boo);
writeln(file_foo_info);
```
To make it easier to read/write code in D, I would introduce new 
mixins. These mixins can only represent identifiers. Also, the 
advantage of such mixins, the parser and semantic analysis will 
be able to detect some errors before the code is completely 
"opened". Also, I think they can speed up compilation.
Jan 29 2022
next sibling parent reply bauss <jj_1337 live.dk> writes:
On Saturday, 29 January 2022 at 21:24:09 UTC, mesni wrote:
 ```d
 static foreach(name; ["boo", "foo"]){
     string file_#name = readText(name~".txt");
     string file_#name

 }

 writeln(file_boo);
 writeln(boo);
 writeln(file_foo_info);
 ```
 To make it easier to read/write code in D, I would introduce 
 new mixins. These mixins can only represent identifiers. Also, 
 the advantage of such mixins, the parser and semantic analysis 
 will be able to detect some errors before the code is 
 completely "opened". Also, I think they can speed up 
 compilation.
I believe a DIP would be necessary, but to be honest I don't see a reason for this. You can just do this which isn't really much less readable. ```d static foreach (name; ["boo", "foo"]) { mixin(`string file_%1$s = readText("%1$s.txt");`.format(name)); } writeln(file_boo); writeln(file_foo); ``` And if D ever gets interpolated strings then the whole format can be removed and it could probably become something like this: ```d static foreach (name; ["boo", "foo"]) { mixin(i`string file_$name = readText("$name.txt");`); } writeln(file_boo); writeln(file_foo); ``` So personally I don't see a reason for your suggestion to be added. I think it's just going to introduce more complexity than it's worth.
Jan 30 2022
next sibling parent reply Paul Backus <snarwin gmail.com> writes:
On Monday, 31 January 2022 at 07:19:49 UTC, bauss wrote:
 I believe a DIP would be necessary, but to be honest I don't 
 see a reason for this.

 You can just do this which isn't really much less readable.

 ```d
     static foreach (name; ["boo", "foo"])
     {
         mixin(`string file_%1$s = 
 readText("%1$s.txt");`.format(name));
     }

     writeln(file_boo);
     writeln(file_foo);
 ```
Using `std.format` for this incurs a substantial compile-time performance penalty--dozens of templates must be instantiated, memory must be allocated for CTFE, the format string must be validated, etc. If the mixin is inside a template which is itself instantiated many times, this overhead can really add up.
Jan 31 2022
next sibling parent reply bachmeier <no spam.net> writes:
On Monday, 31 January 2022 at 20:45:53 UTC, Paul Backus wrote:
 On Monday, 31 January 2022 at 07:19:49 UTC, bauss wrote:
 I believe a DIP would be necessary, but to be honest I don't 
 see a reason for this.

 You can just do this which isn't really much less readable.

 ```d
     static foreach (name; ["boo", "foo"])
     {
         mixin(`string file_%1$s = 
 readText("%1$s.txt");`.format(name));
     }

     writeln(file_boo);
     writeln(file_foo);
 ```
Using `std.format` for this incurs a substantial compile-time performance penalty--dozens of templates must be instantiated, memory must be allocated for CTFE, the format string must be validated, etc. If the mixin is inside a template which is itself instantiated many times, this overhead can really add up.
You have to balance that (which in the absence of benchmarks or other empirical evidence is a theoretical problem) against the horrendous cost in terms of complexity of the language. It's not just the syntax - which would be a substantial burden for new users - but also understanding the details of what it's doing. It's hard to see this being worthwhile for only gains in compilation time.
Jan 31 2022
next sibling parent Paul Backus <snarwin gmail.com> writes:
On Tuesday, 1 February 2022 at 01:52:25 UTC, bachmeier wrote:
 You have to balance that (which in the absence of benchmarks or 
 other empirical evidence is a theoretical problem) against the 
 horrendous cost in terms of complexity of the language. It's 
 not just the syntax - which would be a substantial burden for 
 new users - but also understanding the details of what it's 
 doing. It's hard to see this being worthwhile for only gains in 
 compilation time.
This is a fair criticism of the original proposal. However, allowing the standard string mixin syntax to be used for identifiers in declarations, as suggested by Nick Treleaven in [his reply][1], would bring the same benefits with significantly less complexity. [1]: https://forum.dlang.org/post/aznmkielsozvfgrzehoc forum.dlang.org
Jan 31 2022
prev sibling next sibling parent mesni <mensikovk817 gmail.com> writes:
On Tuesday, 1 February 2022 at 01:52:25 UTC, bachmeier wrote:
 You have to balance that (which in the absence of benchmarks or 
 other empirical evidence is a theoretical problem) against the 
 horrendous cost in terms of complexity of the language. It's 
 not just the syntax - which would be a substantial burden for 
 new users - but also understanding the details of what it's 
 doing. It's hard to see this being worthwhile for only gains in 
 compilation time.
IMHO, in the long term, reading code like this with C like format will take more than memorizing a few rules.
Feb 02 2022
prev sibling parent mesni <mensikovk817 gmail.com> writes:
On Tuesday, 1 February 2022 at 01:52:25 UTC, bachmeier wrote:
 You have to balance that (which in the absence of benchmarks or 
 other empirical evidence is a theoretical problem) against the 
 horrendous cost in terms of complexity of the language. It's 
 not just the syntax - which would be a substantial burden for 
 new users - but also understanding the details of what it's 
 doing. It's hard to see this being worthwhile for only gains in 
 compilation time.
IMHO, in the long term, reading code like this with C like format will take more than memorizing a few rules.
Feb 02 2022
prev sibling next sibling parent reply Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Monday, 31 January 2022 at 20:45:53 UTC, Paul Backus wrote:
 Using `std.format` for this incurs a substantial compile-time 
 performance penalty--dozens of templates must be instantiated, 
 memory must be allocated for CTFE, the format string must be 
 validated, etc. If the mixin is inside a template which is 
 itself instantiated many times, this overhead can really add up.
String mixins should be discouraged, not encouraged. Adding more band aids or special cases is not the right approach. If compile time string processing is the root issue then one shouldn't solve that by changing the semantics of mixin(). That performance issue can be fixed by introducing classic string interpolation.
Feb 02 2022
parent reply Nick Treleaven <nick geany.org> writes:
On Wednesday, 2 February 2022 at 12:19:57 UTC, Ola Fosheim 
Grøstad wrote:
 String mixins should be discouraged, not encouraged. Adding 
 more band aids or special cases is not the right approach.
String mixins can be used for declarations, expressions or types. The special case is actually that they can't be used for an identifier. People even expect that to work - from the learn forum: https://forum.dlang.org/thread/ngfkwcyqjtnqhofoqrew forum.dlang.org
 If compile time string processing is the root issue then one 
 shouldn't solve that by changing the semantics of mixin(). That 
 performance issue can be fixed by introducing classic string 
 interpolation.
String interpolation would be pretty much just as bad for performance because it still requires the entire declaration to be put in a string, rather than just an identifier. That whole string needs to be formatted and turned into code, when we'd rather be reading code in the first place!
Feb 02 2022
parent reply Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Wednesday, 2 February 2022 at 12:24:32 UTC, Nick Treleaven 
wrote:
 String interpolation would be pretty much just as bad for 
 performance because it still requires the entire declaration to 
 be put in a string, rather than just an identifier. That whole 
 string needs to be formatted and turned into code, when we'd 
 rather be reading code in the first place!
If you have to use a *mixin* for an identifier on a regular basis then that suggests to me that something is wrong with the design of the application or that some other language feature is missing. *mixin* should be viewed as an emergency escape hatch compenstating for language deficiencies, not as a solution.
Feb 02 2022
next sibling parent Patrick Schluter <Patrick.Schluter bbox.fr> writes:
On Wednesday, 2 February 2022 at 13:13:13 UTC, Ola Fosheim 
Grøstad wrote:
 On Wednesday, 2 February 2022 at 12:24:32 UTC, Nick Treleaven 
 wrote:
 String interpolation would be pretty much just as bad for 
 performance because it still requires the entire declaration 
 to be put in a string, rather than just an identifier. That 
 whole string needs to be formatted and turned into code, when 
 we'd rather be reading code in the first place!
If you have to use a *mixin* for an identifier on a regular basis then that suggests to me that something is wrong with the design of the application or that some other language feature is missing. *mixin* should be viewed as an emergency escape hatch compenstating for language deficiencies, not as a solution.
Yes, exactly. Mixin variable names as used here is imho a code smell. The variables are parametrized by a name and that is probably better solved by an array indexed on an enum, or a structure or even by an associative array.
Feb 02 2022
prev sibling parent reply Nick Treleaven <nick geany.org> writes:
On Wednesday, 2 February 2022 at 13:13:13 UTC, Ola Fosheim 
Grøstad wrote:
 If you have to use a *mixin* for an identifier on a regular 
 basis
No one said that. It is only to replace using a mixin string for an entire declaration. If you hate mixin strings logically you should not oppose something which restricts their use to a much smaller scope. I do not buy any argument that it would encourage mixin strings. In metaprogramming you do what is necessary for best runtime performance.
Feb 02 2022
parent Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Wednesday, 2 February 2022 at 16:24:25 UTC, Nick Treleaven 
wrote:
 much smaller scope. I do not buy any argument that it would 
 encourage mixin strings. In metaprogramming you do what is 
 necessary for best runtime performance.
I agree with the concern for runtime performance, but if that really is an issue then maybe it would better to instead improve on the language rather than adding more string-manipulation.
Feb 05 2022
prev sibling parent Atila Neves <atila.neves gmail.com> writes:
On Monday, 31 January 2022 at 20:45:53 UTC, Paul Backus wrote:
 On Monday, 31 January 2022 at 07:19:49 UTC, bauss wrote:
 I believe a DIP would be necessary, but to be honest I don't 
 see a reason for this.

 You can just do this which isn't really much less readable.

 ```d
     static foreach (name; ["boo", "foo"])
     {
         mixin(`string file_%1$s = 
 readText("%1$s.txt");`.format(name));
     }

     writeln(file_boo);
     writeln(file_foo);
 ```
Using `std.format` for this incurs a substantial compile-time performance penalty--dozens of templates must be instantiated, memory must be allocated for CTFE, the format string must be validated, etc. If the mixin is inside a template which is itself instantiated many times, this overhead can really add up.
mixin(`string file_`, name, ` = readText("`, name, `.txt");`);
Feb 07 2022
prev sibling parent reply Quirin Schroll <qs.il.paperinik gmail.com> writes:
On Monday, 31 January 2022 at 07:19:49 UTC, bauss wrote:
 On Saturday, 29 January 2022 at 21:24:09 UTC, mesni wrote:
 ```d
 static foreach(name; ["boo", "foo"]){
     string file_#name = readText(name~".txt");
     string file_#name

 }

 writeln(file_boo);
 writeln(boo);
 writeln(file_foo_info);
 ```
 To make it easier to read/write code in D, I would introduce 
 new mixins. These mixins can only represent identifiers. Also, 
 the advantage of such mixins, the parser and semantic analysis 
 will be able to detect some errors before the code is 
 completely "opened". Also, I think they can speed up 
 compilation.
I believe a DIP would be necessary, but to be honest I don't see a reason for this. You can just do this which isn't really much less readable. ```d static foreach (name; ["boo", "foo"]) { mixin(`string file_%1$s = readText("%1$s.txt");`.format(name)); } writeln(file_boo); writeln(file_foo); ``` And if D ever gets interpolated strings then the whole format can be removed and it could probably become something like this: ```d static foreach (name; ["boo", "foo"]) { mixin(i`string file_$name = readText("$name.txt");`); } writeln(file_boo); writeln(file_foo); ``` So personally I don't see a reason for your suggestion to be added. I think it's just going to introduce more complexity than it's worth.
One big disadvantage interpolated strings have is you have to put the full declaration in a string. No big deal for a statement, but if the name of a function depends on compile-time stuff, the whole function is a string. A much easier solution to this is allowing `mixin()` as an `Identifier` in general: ```diff Identifier: IdentifierStart IdentifierStart IdentifierChars + MixinExpression ``` So, you'd do ```d static foreach(name; ["boo", "foo"]) { enum string file_name_info = "file_" ~ name ~ "_info"; string mixin("file_", name) = readText(name ~ ".txt"); string mixin(file_name_info) = readText(name ~ ".meta"); auto mixin(name) = mixin(file_name_info).parseInfoFile; } ```
Feb 07 2022
next sibling parent bauss <jj_1337 live.dk> writes:
On Monday, 7 February 2022 at 10:49:13 UTC, Quirin Schroll wrote:
 On Monday, 31 January 2022 at 07:19:49 UTC, bauss wrote:
 On Saturday, 29 January 2022 at 21:24:09 UTC, mesni wrote:
 ```d
 static foreach(name; ["boo", "foo"]){
     string file_#name = readText(name~".txt");
     string file_#name

 }

 writeln(file_boo);
 writeln(boo);
 writeln(file_foo_info);
 ```
 To make it easier to read/write code in D, I would introduce 
 new mixins. These mixins can only represent identifiers. 
 Also, the advantage of such mixins, the parser and semantic 
 analysis will be able to detect some errors before the code 
 is completely "opened". Also, I think they can speed up 
 compilation.
I believe a DIP would be necessary, but to be honest I don't see a reason for this. You can just do this which isn't really much less readable. ```d static foreach (name; ["boo", "foo"]) { mixin(`string file_%1$s = readText("%1$s.txt");`.format(name)); } writeln(file_boo); writeln(file_foo); ``` And if D ever gets interpolated strings then the whole format can be removed and it could probably become something like this: ```d static foreach (name; ["boo", "foo"]) { mixin(i`string file_$name = readText("$name.txt");`); } writeln(file_boo); writeln(file_foo); ``` So personally I don't see a reason for your suggestion to be added. I think it's just going to introduce more complexity than it's worth.
One big disadvantage interpolated strings have is you have to put the full declaration in a string. No big deal for a statement, but if the name of a function depends on compile-time stuff, the whole function is a string. A much easier solution to this is allowing `mixin()` as an `Identifier` in general: ```diff Identifier: IdentifierStart IdentifierStart IdentifierChars + MixinExpression ``` So, you'd do ```d static foreach(name; ["boo", "foo"]) { enum string file_name_info = "file_" ~ name ~ "_info"; string mixin("file_", name) = readText(name ~ ".txt"); string mixin(file_name_info) = readText(name ~ ".meta"); auto mixin(name) = mixin(file_name_info).parseInfoFile; } ```
Yeah, I'm definitely not against mixin working for identifiers. My example was as a solution if it's never accepted.
Feb 07 2022
prev sibling parent Daniel N <no public.email> writes:
On Monday, 7 February 2022 at 10:49:13 UTC, Quirin Schroll wrote:
 A much easier solution to this is allowing `mixin()` as an 
 `Identifier` in general:

 ```diff
  Identifier:
      IdentifierStart
      IdentifierStart IdentifierChars
 +    MixinExpression
 ```

 So, you'd do

 ```d
 static foreach(name; ["boo", "foo"])
 {
     enum string file_name_info = "file_" ~ name ~ "_info";
     string mixin("file_", name) = readText(name ~ ".txt");
     string mixin(file_name_info) = readText(name ~ ".meta");
     auto mixin(name) = mixin(file_name_info).parseInfoFile;
 }
 ```
This looks fantastic!
Feb 07 2022
prev sibling parent Nick Treleaven <nick geany.org> writes:
On Saturday, 29 January 2022 at 21:24:09 UTC, mesni wrote:
 ```d
 static foreach(name; ["boo", "foo"]){
     string file_#name = readText(name~".txt");
     string file_#name

 }
A general feature for this has been suggested several times before by various people (initially in 2009!). (I noticed your syntax above seems to flip the meanings of the C preprocessor identifier is expected. It was mentioned in the `static foreach` DIP: https://github.com/dlang/DIPs/blob/master/DIPs/accepted/DIP1010.md#mixin-identifiers The nice thing about re-using string `mixin` syntax for this is that (since then) it can take multiple arguments which the compiler concatenates. So this would work: ```d static foreach(n; [1,2,3]) { int mixin("foo", n) = n; } assert(foo1 == 1); ```
 To make it easier to read/write code in D, I would introduce 
 new mixins. These mixins can only represent identifiers. Also, 
 the advantage of such mixins, the parser and semantic analysis 
 will be able to detect some errors before the code is 
 completely "opened". Also, I think they can speed up 
 compilation.
Yes, parsing would be a bit quicker vs putting the whole declaration in a string with CTFE string concatenation. Parsing error messages would be much easier to deal with, besides the likelihood of errors being lower anyway as the code would be much more readable.
Jan 31 2022