digitalmars.D - X macro in D
- Walter Bright (12/12) Aug 20 2022 The X macro in C is famous:
- Timon Gehr (31/49) Aug 20 2022 Not much of a challenge.
- Tejas (3/8) Aug 20 2022 Are our IDEs/LSPs still capable of providing autocomplete
- Adam D Ruppe (3/5) Aug 20 2022 The beauty of the reflection approaches is the code just remains
- Paul Backus (42/55) Aug 20 2022 Here's an implementation of the color example in D:
The X macro in C is famous: https://www.digitalmars.com/articles/b51.html Here's the challenge: "X-macros in C [1] are great for doing compile-time code generation from tabular data. Especially for things like pinouts and their respective capabilities on microcontrollers, I haven't seen any other language give such a succinct, easily maintainable way of interacting and representing data such that it can be used for full function generation that an IDE can autocomplete names, types etc. Sure there are other "newer" ways but they invariably involve so much boilerplate that you might as well just write all the code by hand." https://news.ycombinator.com/item?id=32530255 Who is up for the challenge?
Aug 20 2022
On 8/20/22 15:11, Walter Bright wrote:The X macro in C is famous: https://www.digitalmars.com/articles/b51.html Here's the challenge: "X-macros in C [1] are great for doing compile-time code generation from tabular data. Especially for things like pinouts and their respective capabilities on microcontrollers, I haven't seen any other language give such a succinct, easily maintainable way of interacting and representing data such that it can be used for full function generation that an IDE can autocomplete names, types etc. Sure there are other "newer" ways but they invariably involve so much boilerplate that you might as well just write all the code by hand." https://news.ycombinator.com/item?id=32530255 Who is up for the challenge?Not much of a challenge. Your example: ```d enum Color { red, blue, green } static immutable colorStrings = [EnumMembers!Color].map!text.array; static foreach(color;EnumMembers!Color){ ... } ``` Example 1 from Wikipedia: ```d auto value1=1,value2=2,value3=3; alias vars=AliasSeq!(value1,value2,value3); void printVariables(){ static foreach(alias var;vars){ writeln(__traits(identifier, var), " = ", var); } } ``` Example 2 from Wikipedia: enum id1=1, id2=2, id3=3; static immutable varList = [ tuple("id1", "name1"), tuple("id2", "name2"), tuple("id3", "name3"), ]; static foreach(id, name; varList.map!(x=>x)){ // yuck mixin(`int `~name~`;`); } mixin(`enum MyIdListType{`~varList.map!(x=>x[1]~"="~x[0]).join(",")~`}`); Does not allow you to add new columns transparently, but I guess we'd need actual tuple pattern matching for that (or do everything via indices).
Aug 20 2022
On Saturday, 20 August 2022 at 14:15:52 UTC, Timon Gehr wrote:On 8/20/22 15:11, Walter Bright wrote:Are our IDEs/LSPs still capable of providing autocomplete information after all that kind of code though?[...]Not much of a challenge. Your example: [...]
Aug 20 2022
On Saturday, 20 August 2022 at 16:23:47 UTC, Tejas wrote:Are our IDEs/LSPs still capable of providing autocomplete information after all that kind of code though?The beauty of the reflection approaches is the code just remains the code and works normally including the auto complete.
Aug 20 2022
On Saturday, 20 August 2022 at 13:11:43 UTC, Walter Bright wrote:The X macro in C is famous: https://www.digitalmars.com/articles/b51.html Here's the challenge: "X-macros in C [1] are great for doing compile-time code generation from tabular data. Especially for things like pinouts and their respective capabilities on microcontrollers, I haven't seen any other language give such a succinct, easily maintainable way of interacting and representing data such that it can be used for full function generation that an IDE can autocomplete names, types etc. Sure there are other "newer" ways but they invariably involve so much boilerplate that you might as well just write all the code by hand."Here's an implementation of the color example in D: import std.traits, std.meta; enum Color { red, blue, green } enum getName(alias sym) = __traits(identifier, sym); string[] colorStrings = [staticMap!(getName, EnumMembers!Color)]; unittest { assert(colorStrings[Color.red] == "red"); assert(colorStrings[Color.blue] == "blue"); assert(colorStrings[Color.green] == "green"); } Since we have access to powerful compile-time reflection in D, we can let the enum be the "source of truth", and just generate the array. Ok, but what if we want to use names for the enum members that aren't identical to their string representation? Simple: import std.traits, std.meta; struct name { string str; } enum Color { name("red") Cred, name("blue") Cblue, name("green") Cgreen } enum getName(alias sym) = getUDAs!(sym, name)[0].str; string[] colorStrings = [staticMap!(getName, EnumMembers!Color)]; unittest { assert(colorStrings[Color.Cred] == "red"); assert(colorStrings[Color.Cblue] == "blue"); assert(colorStrings[Color.Cgreen] == "green"); } In C, each additional "column" of data is represented as an additional argument to the X macro. Since D's UDAs let us attach arbitrary data to any symbol, including enum members, we can turn those additional arguments into attributes of the enum members, and once again use the enum itself as the source of truth. (These examples also show off the utility of D's built-in unit tests, for checking our work.)
Aug 20 2022