Passing variables, preserving UDAs: A Gripe

Nick Sabalausky via Digitalmars-d digitalmars-d at puremagic.com
Tue Feb 7 13:59:49 PST 2017


Suppose I have some code that operates on a variable's value and its 
UDAs. And I want to refactor that code into a reusable function. Sounds 
simple enough, right?

So, consider a basic example:

----------------------------
class Foo
{
     @("Hello")
     string s;
}

void doStuff(alias var)()
{
     var = "abc";

     import std.traits;
     assert(hasUDA!(var, "Hello") == true);
}

void main()
{
     @("Hello")
     string s;
     doStuff!(s);

     auto foo = new Foo();
     // Error: need 'this' for 'doStuff' of type 'pure nothrow @nogc 
@safe void()'
     doStuff!(foo.s);
}
----------------------------

Note the error. Naturally, that cannot compile, because you can't 
instantiate a template based on the value of a variable at runtime (ie, 
based on the value of `foo`).

This can be made to *compile* if you pass by runtime ref instead of alias:

----------------------------
void doStuff(T)(ref T var)
{
     var = "abc";

     import std.traits;
     assert(hasUDA!(var, "Hello") == true); // Fail!
}

void main()
{
     auto foo = new Foo();
     doStuff(foo.s); // Ok
}
----------------------------

But as expected, the UDAs are not preserved because UDAs are attached to 
declarations, not values.

This CAN be made to work, albeit very awkwardly:

----------------------------
class Foo
{
     @("Hello")
     string s;
}

void doStuff(alias var)()
{
     var = "abc";

     import std.traits;
     assert(hasUDA!(var, "Hello") == true);
}

void doStuffMember(string memberName, ObjType)(ObjType obj)
{
     __traits(getMember, obj, memberName) = "abc";

     import std.traits;
     assert(hasUDA!(__traits(getMember, obj, memberName), "Hello") == true);
}

void main()
{
     @("Hello")
     string s;
     doStuff!(s);

     auto foo = new Foo();
     doStuffMember!("s")(foo);
}
----------------------------

But now it's:

1. A complete freaking mess

2. An unintuitively inconsistent interface

3. A blatant DRY violation

4. AFAICS, cannot be DRY-ed up particularly well without either running 
into the original problem, resorting to string mixins (which comes with 
its own problems), or saying "to hell with using D's UDA interfaces 
within my function" and just passing the result of getUDAs into the 
function to be used instead, and recreating stuff like hasUDA to operate 
on the results of getUDAs instead of the symbols directly.

5. Did I mention it's A COMPLETE FREAKING MESS for what seems like a 
very simple problem?



More information about the Digitalmars-d mailing list