I want to add a Phobos module with template mixins for common idioms.

Idan Arye GenericNPC at gmail.com
Tue May 7 12:10:22 PDT 2013


On Tuesday, 7 May 2013 at 08:58:47 UTC, Dicebot wrote:
> I really think that UDA annotations + single mixin like this:
>
> class Test
> {
>     private:
>         // annotated stuff
>     public:
>     mixin implementAnnotations!Test;
> }
>
> is a most type-safe approach which scales.

I think any method will scale(except for insane methods like 
inheriting from a templated class that receives the properties 
schema via template arguments...). After all - we are dealing 
with declarations here, and we can't stuck as many as we want 
while still keeping the code readable.

The problem with any solution that declares the fields directly 
in the struct\class's body is that the field identifier 
overshadows the property methods. If we look at your example, and 
declare a field to be made into a property:

     class Test
     {
         private:
             @Property int foo;
         public:
             mixin implementAnnotations!Test;
     }

Now, the expected behavior is that `implementAnnotations!Test` 
will declare a getter and a setter, both named `foo`. But even if 
it does that, it won't do us any good - because the accessors are 
declared inside a mixin, so they are overshadowed by the same 
`foo` we wanted to encapsulate!

So, we have to change it:

     class Test
     {
         private:
             @Property int m_foo;
         public:
             mixin implementAnnotations!Test;
     }

and inside `implementAnnotations` we would have to strip `m_foo` 
out of it's prefix to get the getter&setter names.


If we send a token string to the mixin template, we can avoid 
this problem:

     class Test
     {
         public:
             mixin properties!q{
                 int foo;
             }
     }

And what happens inside the `properties` mixin is:

     mixin template properties(string declaration){
         private struct __Fields
         {
             mixin(declaration);
         }
         private __Fields __fields;
         // Create accessors properties for __fields's members.
         // Possibly create "m_*" aliases for __fields's members.
     }

Now the `foo` is not declared directly inside `Test` - instead it 
is declared inside `Test.__Fields` and accessed via the 
`__fields` struct. That means we are free to name our accessor 
property methods `foo` - since that identifier is still available 
in the main namespace of `Test`.

This solution has two problems(beside "x is evil" mantras):

1) Since the properties are created inside a struct, trying to 
probe `Test`(like `tupleof` or `std.traits.FieldTypeTuple`) will 
yield weird results. I believe I can solve this with a slightly 
more complex approach - instead of creating a member instance of 
`__Fields`, I can probe it myself and create `m_*` variations of 
the properties with the same types, storage classes etc.

2) If you use `typeof(this)` while declaring a property, it will 
yield `__Fields` instead of `Test`. I don't really know how to 
solve this, but this is an edge case - `typeof(this)` is usually 
used in mixins or templated methods, not in field declaration - 
so even with this problem, the mixin+string version is better 
suited for the common use-case.

Anyways, a small enhancement to dmd can help solve both problems 
easily - a mixin template that has an identifier and does not 
leak to the surrounding scope. But even without it - I can solve 
the first problem and the second problem concerns a rare 
use-case, so this is still a good solution if we want to declare 
the properties with the same names we are going to use them 
with...


More information about the Digitalmars-d mailing list