On Thursday, 31 January 2013 at 16:44:03 UTC, TommiT wrote:
So, going back to the concept of property as a crossbreed between a namespace and a variable. Here's my new take on it:

* Property looks like a namespace when it is defined, and a variable when it is used.

* Property definition creates its own lexical scope.

* Properties can't hold any variables, don't take up any memory, and you can't take the address of a property.

* Properties may have a special opGet operator that will be called eagerly whenever a naked property is used, i.e. a property is used without applying any such operator or member function that is defined for that particular property.

I don't know if properties really need to have member functions, but I wouldn't want to rule them out right off the bat.

struct T
{
    private int value;

    bool isCorrect() const
    {
        return false;
    }

    property myProp
    {
        // the special "eager casting operator" of properties
        int opGet() const
        {
            return value;
        }

        void opAssign(int v)
        {
            value = v;
            // doesn't have to return anything
        }

        void opAssign(string s : "+")(int v)
        {
            // 'this' refers to the enclosing object
            this.value += v;
        }

        // function attribute 'const' refers to the
        // constness of the enclosing object
        bool isCorrect() const
        {
            return value == 42;
        }

        ref T sayWhat()
        {
            // isCorrect refers to: this.myProp.isCorrect
            // ...and not to:       this.isCorrect
            assert(isCorrect());

            // 'this' refers to the enclosing object
            return this;
        }

        int data; // error: properties can't hold any variables
    }
}

void foo(T : int)(T t);

int fn(T.myProp p); // error: T.myProp is a property, not a type

...

T t;
foo(t.myProp);     // foo(t.myProp.opGet());
auto v = t.myProp; // int v = t.myProp.opGet();
t.myProp = 41;     // t.myProp.opAssign(41);
t.myProp += 1;     // t.myProp.opAssign!"+"(41);
assert(t.myProp.isCorrect());

immutable T t2;
t2.myProp.sayWhat(); // error: cannot call a non-const property
                     // method of an immmutable variable t2

Here's some more elaboration of the interplay between 1) "naked" property use, 2) property methods/operators and 3) the methods/operators of the type which "naked" property use returns through the opGet operator:

struct Speed
{
    int _value;

    void opOpAssign(string op)(int rhs)
        if (op == "+")
    {
        _value += rhs;
        assert(1 <= _value && _value <= 4);
    }
}

struct Sneak
{
    int _value;

    void opOpAssign(string op)(int rhs)
        if (op == "+")
    {
        _value += rhs;
        assert(1 <= _value && _value <= 4);
    }
}

struct Character
{
    private Speed _speed;
    private Sneak _sneak;

    property speed
    {
        ref Speed opGet()
        {
            return _speed;
        }

        void opOpAssign(string op)(int rhs)
            if (op == "+")
        {
            _speed += rhs;
            assert(_speed._value + _sneak._value <= 5);
        }
    }

    property sneak
    {
        ref Sneak opGet()
        {
            return _sneak;
        }
    }
}

void main()
{
    Character c;

    c.speed += 1; // calls: c.speed.opOpAssign!"+"(1);
    c.sneak += 1; // calls: c.sneak.opGet() += 1;
                  // i.e.   c._sneak.opOpAssign!"+"(1);
}

As far as I know, the obove kind of thing isn't possible with the current state of affairs; with @property attribute, you cannot provide the extra level of encapsulation that checks that the sum of 'speed' and 'sneak' isn't above 5.

Reply via email to