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.