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