Partial modification of DIP23 to allow module level property

Kenji Hara k.hara.pg at gmail.com
Fri Feb 8 21:15:34 PST 2013


> http://wiki.dlang.org/DIP23

I had thought about DIP23 for a while, to allow module-level 
property function.
As the conclusion, we can have that without breaking the essence 
in DIP23.

==========

> In a nutshell
> 2. A @property may have EXACTLY ONE or EXACTLY TWO parameters, 
> counting the implicit this parameter if at all.
> The ONE-parameter version is ALWAYS a getter, and the 
> TWO-parameter version is ALWAYS a setter.
> There's no variadics, defaulted parameters, and such.

We should change this sentence to:
----
2. A @property may have EXACTLY ZERO or EXACTLY ONE parameter, 
without counting the implicit this parameter if at all.
The ZERO-parameter version is ALWAYS a getter, and the 
ONE-parameter version is ALWAYS a setter.
There's no variadics, defaulted parameters, and such.
----

> Optional parens stay in

No modification is necessary.

> No module-level properties

It should be replaced to completely:
----
* Module level properties stay in

There is still module-level property emulating a global variable.
That means a @property defined at module level must take either 
ZERO parameter (meaning its a getter) or ONE parameter (meaning 
it's a setter).

// at module level
private long _distance;
@property long distance() { return _distance; }
@property void distance(double d) { assert(d >= 0); _distance = 
cast(long)std.math.trunc(d); }
unittest
{
     distance = 3.1;
     assert(_distance == 3)
     auto d = distance;
     assert(d == 3);
}

To avoid syntactic ambiguity, it's forbidden to define property 
getter callable by using UFCS.

@property ref int front(int[] a) { return a[0]; }
unittest
{
     int[] arr = [1,2,3];
     assert(front(arr) == 1);  // OK
     assert(arr.front == 1);   // compile-time error, "setter 
@property function cannot call with UFCS"
}

Instead, such 'front' function would work if remove the @property 
annotation.

ref int front(int[] a) { return a[0]; }
unittest
{
     int[] arr = [1,2,3];
     assert(front(arr) == 1);   // OK
     assert(arr.front() == 1);  // OK, UFCS
     assert(arr.front == 1);    // Even OK, UFCS + optional 
paranthesis feature

     arr.front() = 2;      // assign to returned ref
     assert(arr[0] == 2);
     arr.front = 3;        // Even OK, optional parenthesis
     assert(arr[0] == 2);

     int* p = &arr.front;  // Even OK, arr.front is rewritten to
     // front(arr), so '&' operator will be applied to the ref 
value returned from 'front'.
}

For the combination of UFCS and setter syntax, a function which 
takes TWO parameters and defined at module level can SPECIALLY be 
annotated with @property.

@property void all(double[] x, int y) { x[] = cast(double) y; }
unittest
{
     auto d = [ 1.2, 3.4 ];
     d.all = 42;  // UFCS + setter syntax
                  // rewritten to: all(d, 42)
     assert(d == [ 42.0, 42.0 ]);
}
----

Regards.

Kenji Hara


More information about the Digitalmars-d mailing list