www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Deriving a struct from another one via template: Easy way to propagate

reply Inkrementator <anon example.org> writes:
Hello,
I am trying to derive a struct from another. I want to modify 
each field such that type of it goes from some T to Nullable!T, 
preserving all fieldnames and UDAs.

I think that fieldnames and UDAs can only be duplicated via 
string-mixins. This means that all field-types that aren't 
visible in the template scope have to first be aliased to some 
name that can be referenced in the string mixin. I got this to 
work for simple types, but as soon as the field types are some 
templated type, doing this naively stops to work.
Same story for UDAs. As soon as multiple unknown types are 
involved, I can't simply take an alias anymore.

The one workaround I found is to make my introspective struct 
part of a template mixin, this way it can access all symbols of 
the callsite and can use all the symbols. Is this the recommended 
way to do it? Generating a string mixin directly would probably 
work just as well, but that seems even more ugly and will 
probably be more susceptible to collisions.

This not so simple gist demonstrates what I tried so far. 
injectedNameFields generates a string that when mixed in, will 
create all the field names with the desired types. I suggest 
first looking at main and compiling+running to get an idea what 
is supposed to happen.
https://gitlab.com/-/snippets/3687470

After describing my problem, here is a non-exhaustive list of 
questions I have:
* Is UDA propagation possible without string mixins?
* To make it run without template mixin, I will need to write a 
recursive template (recursive over template args as well as UDA 
instantiated structs) that accounts for cases: normal type, 
templated type, enum (C style), enum value compile time constant, 
etc. ... Is this correct, or is there a way to just grab any 
compile time alias/enum without giving each "type" special 
treatment?
* Are template mixins vulnerable to name collisions?
Mar 14
next sibling parent reply cc <cc nevernet.com> writes:
On Thursday, 14 March 2024 at 23:19:37 UTC, Inkrementator wrote:
 I am trying to derive a struct from another. I want to modify 
 each field such that type of it goes from some T to Nullable!T, 
 preserving all fieldnames and UDAs.
This is trivially easy if your types are visible at module level, and mixin is a fine tool for the job. It doesn't work quite so well with [Voldemort types](https://wiki.dlang.org/Voldemort_types). ```d struct MyUDA { int q; } struct Foo { int f; } struct MyStruct { MyUDA(3) int x; MyUDA(4) Foo f; MyUDA(5) MyUDA(7) string s; } auto generateUDAs(A...)() { string[] udaStrs; static foreach (uda; A) udaStrs ~= " (" ~ uda.stringof ~ ")"; return udaStrs; } struct Wrapped(S) { static foreach (idx, field; S.tupleof) { //pragma(msg, format(... can be used to preview mixin(format("%s %s %s;", generateUDAs!(__traits(getAttributes, field)).join(' '), Nullable!(typeof(field)).stringof, field.stringof)); } } void main() { MyStruct s; s.x = 3; s.f = Foo(1); s.s = null; Wrapped!MyStruct w; w.x = s.x; w.f = s.f; w.s = s.s; w.x.nullify; w.f.nullify; w.s.nullify; // strings/objects are already nullable though static assert(__traits(getAttributes, w.s) == AliasSeq!(MyUDA(5), MyUDA(7))); } ``` If you absolutely must though, you could do something like ```d enum WrapMixin = q{ struct Wrapped(S) { static foreach (field; S.tupleof) mixin(format("%s %s %s;", generateUDAs!(__traits(getAttributes, field)).join(' '), Nullable!(typeof(field)).stringof, field.stringof)); } }; void main() { struct MyUDA { ..... struct MyStruct { ..... mixin(WrapMixin); Wrapped!MyStruct w; } ```
Mar 15
parent Inkrementator <anon example.org> writes:
On Friday, 15 March 2024 at 19:13:38 UTC, cc wrote:
 This is trivially easy if your types are visible at module 
 level, and mixin is a fine tool for the job.  It doesn't work 
 quite so well with [Voldemort 
 types](https://wiki.dlang.org/Voldemort_types).
I used the following lines to make it work for Unknown and I think even Voldemort types. ```d static foreach(att; allFieldTypes){ //pragma(msg, "alias %s =att;\n".format(att.stringof)); mixin("alias %s = att;\n".format(att.stringof)); } ``` But I don't know how to do this (in a general) for UDAs, since they can be values instead of types too, i.e. UDA(Voldemort!2(3))
Mar 16
prev sibling parent reply Adam D Ruppe <destructionator gmail.com> writes:
On Thursday, 14 March 2024 at 23:19:37 UTC, Inkrementator wrote:
 * Is UDA propagation possible without string mixins?
(__traits(getAttributes, thingYouWantToForward)) void yourNewThing() {}
 * Are template mixins vulnerable to name collisions?
http://dpldocs.info/this-week-in-d/Blog.Posted_2020_01_20.html#understanding-mixin-templates
Mar 16
parent reply Inkrementator <anon example.org> writes:
On Saturday, 16 March 2024 at 13:09:13 UTC, Adam D Ruppe wrote:
 On Thursday, 14 March 2024 at 23:19:37 UTC, Inkrementator wrote:
  (__traits(getAttributes, thingYouWantToForward))
 void yourNewThing() {}
Thanks, that should solve my problem.
 http://dpldocs.info/this-week-in-d/Blog.Posted_2020_01_20.html#understanding-mixin-templates
Nice. Btw I vaguely remember you also wrote about how and why to reduce the usage string mixins, with some real example of alternative techniques you used, but I can't find it anymore. The search query 'site:dpldocs.info string mixin "This week in D"' as well as "site:arsdnet.net mixin" don't produce it. Can you link it to me?
Mar 16
parent Adam D Ruppe <destructionator gmail.com> writes:
On Saturday, 16 March 2024 at 20:34:57 UTC, Inkrementator wrote:
 Nice. Btw I vaguely remember you also wrote about how and why 
 to reduce the usage string mixins, with some real example of 
 alternative techniques you used
go to the main page: http://dpldocs.info/this-week-in-d/Blog.html and use ctrl+f and hope i said it in the summary lol but the two that pop up there are: http://dpldocs.info/this-week-in-d/Blog.Posted_2022_12_26.html#more-mixin-techniques and https://forum.dlang.org/post/fbcltjuysmjrxmebeeva forum.dlang.org The general rule is to try to use the local name inside the string instead of concatenating its result, and remember the built in compiler-tuple - which is what __traits(getAttributes) and the parameters reflection and other things - can be used directly in a lot of places, you can very often substitute one of those for a value and it will put it in for you. I encourage you to experiment with plugging these things directly in at the use site and seeing what happens before falling back to strings. fyi don't really follow this forum anymore, you got a bit lucky that i popped in for the dconf online link, so i might not see any further replies to this.
Mar 17