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

Reply via email to