Thread overview
Deriving a struct from another one via template: Easy way to propagate UDAs?
Mar 15
cc
March 14

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?
March 15

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.

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

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

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.
I used the following lines to make it work for Unknown and I think even Voldemort types.

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))

March 16
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?
March 17
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.