May 07, 2013
On 2013-05-07 01:20, Idan Arye wrote:

> However, your idea of having a single mixin handle all the
> class\struct's properties gave me another idea - to use a single mixin,
> but instead of having it analyze the owner class to find the fields we
> want to make properties, we simply give them to it with a token string:
>
>      class Foo
>      {
>          mixin properties!q{
>              @asserting(`a < 50`)     int x = 1;
>              @verifying(`a !is null`) string y = "hello";
>              @privateSetter           double z = 44.4;
>          };
>      }

Please no strings, it's horrible.

-- 
/Jacob Carlborg
May 07, 2013
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.
May 07, 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...
May 07, 2013
On Tuesday, 7 May 2013 at 19:10:23 UTC, Idan Arye wrote:
> 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.

I believe it is exactly how it should be. With changeable compile-time naming convention function.
May 07, 2013
On Tuesday, 7 May 2013 at 19:10:23 UTC, Idan Arye wrote:
> 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.

Actually, forget about that enhancement - I can use aliases, CTFE and a mixin to solve that problem.

On Tuesday, 7 May 2013 at 20:25:21 UTC, Dicebot wrote:
> On Tuesday, 7 May 2013 at 19:10:23 UTC, Idan Arye wrote:
>> 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.
>
> I believe it is exactly how it should be. With changeable compile-time naming convention function.

So this is where we disagree. I believe that if you want a property named `foo` you should be able to just name it `foo` to begin with.
May 08, 2013
OK, so I'm gonna go ahead and implement it, so I can show by example that the string solution can be typesafe, scalable and elegant.
May 10, 2013
On Wednesday, 8 May 2013 at 20:11:34 UTC, Idan Arye wrote:
> OK, so I'm gonna go ahead and implement it, so I can show by example that the string solution can be typesafe, scalable and elegant.

OK, this is a basic implementation:
https://gist.github.com/someboddy/5557358

Before I can make the pull request, I still need to do documentation, add some asserts to make sure users don't declare methods or subtypes in the property declarations string, add some more unit tests, and add the other idiom(the singleton).

But, it's still enough for demonstrating that strings are not evil, and that their usage here does not brake type safety, scope, or anything else.
May 11, 2013
On Friday, 10 May 2013 at 21:04:32 UTC, Idan Arye wrote:
> On Wednesday, 8 May 2013 at 20:11:34 UTC, Idan Arye wrote:
>> OK, so I'm gonna go ahead and implement it, so I can show by example that the string solution can be typesafe, scalable and elegant.
>
> OK, this is a basic implementation:
> https://gist.github.com/someboddy/5557358
>
> Before I can make the pull request, I still need to do documentation, add some asserts to make sure users don't declare methods or subtypes in the property declarations string, add some more unit tests, and add the other idiom(the singleton).
>
> But, it's still enough for demonstrating that strings are not evil, and that their usage here does not brake type safety, scope, or anything else.

That's a very nice syntax. It would be a good start for a mixin library.
May 13, 2013
On Friday, 10 May 2013 at 21:04:32 UTC, Idan Arye wrote:
> On Wednesday, 8 May 2013 at 20:11:34 UTC, Idan Arye wrote:
>> OK, so I'm gonna go ahead and implement it, so I can show by example that the string solution can be typesafe, scalable and elegant.
>
> OK, this is a basic implementation:
> https://gist.github.com/someboddy/5557358
>
> Before I can make the pull request, I still need to do documentation, add some asserts to make sure users don't declare methods or subtypes in the property declarations string, add some more unit tests, and add the other idiom(the singleton).
>
> But, it's still enough for demonstrating that strings are not evil, and that their usage here does not brake type safety, scope, or anything else.

kickass technique, hope this get included soon, keep up the good work!
May 18, 2013
OK, I implemented everything and made a pull request: https://github.com/D-Programming-Language/phobos/pull/1294