On Monday, 20 August 2018 at 00:49:02 UTC, Jonathan M Davis wrote:
On Sunday, August 19, 2018 12:32:17 PM MDT QueenSvetlana via
Digitalmars-d- learn wrote:
In the D Style Guide, it says:
Properties
https://dlang.org/dstyle.html#properties
Functions should be property functions whenever appropriate.
In particular, getters and setters should generally be avoided
in favor of property functions. And in general, whereas
functions should be verbs, properties should be nouns, just
like if they were member variables. Getter properties should
not alter state.
In the Properties function section, it says:
https://dlang.org/spec/function.html#property-functions
WARNING: The definition and usefulness of property functions
is being reviewed, and the implementation is currently
incomplete. Using property functions is not recommended until
the definition is more certain and implementation more mature.
So which is it?
Feel free to use @property or not, but the main point in the
style guide is about naming functions, not about @property. The
idea is that functions that wrap or emulate variables should
act like variables themselves. So, they should be named as if
they were variables and syntactically used as if they were
variables rather than prepending their names with get or set
and calling them as functions. e.g.
struct S
{
int prop() { return _prop; }
int prop(int val) { return _prop = prop; }
private int _prop;
}
with
auto r = s.prop;
s.prop = 42;
instead of
struct S
{
int getProp() { return _prop; }
int setProp(int val) { return _prop = prop; }
private int _prop;
}
auto r = s.getProp();
s.setProp(42).
Marking property functions with @property is an extremely
popular thing to do, but all it really does at this point is
document that the programmer intends for it to be used as a
property rather than enforce anything.
IMHO, the spec words that bit too strongly, and it should be
fixed. That bit got added recently, because one of the devs
didn't understand the @property situation, and when he found
out what it was, he felt that the spec needed to be clarified
about it so that folks didn't think that it was what the spec
was claiming, but clearly, he's just confused matters in a
different way.
Here's the deal. Using the property syntax with functions
really has nothing to do with @property. It's just based on the
signature that a function has. If it's a free function, and it
has a return value but no arguments, without using UFCS, it can
be used as a getter
int prop();
auto r = prop;
If it has a single argument, or it returns by ref, then it can
be used as a setter.
ref int prop();
int prop(int);
void prop(int);
all work with
prop = 42;
though the first two can also be used in chained assignment
operations, since they also return a value, whereas the third
can't be. e.g.
auto foo = prop = 19;
works with the first two but not the third.
All of the same signatures as member functions also work in the
same way except that you then get
auto r = obj.prop;
for the getter and
obj.prop = 42;
for the setter. And if they're free functions, and you want to
use them with UFCS, then they each need one more parameter. e.g.
int prop(MyObj);
auto r = obj.prop;
for the getter and
ref int prop(MyObj);
int prop(MyObj, int);
void prop(MyObj, int);
obj.prop = 42;
for the setter. All of this works regardless of anything to do
with @property and has had since well before @property existed
(well, aside from using it with UFCS, since UFCS came later).
However, a number of folks thought that it was too messy to
allow any old function with the right set of parameters to be
used with the property syntax rather than requiring that it be
part of the API that it be a property function. Probably the
most egregious case is that something like
writeln = 42;
works just fine, and writeln is clearly a function, not a
function emulating a variable (which is what a property
function is supposed to be). So, to improve the situation,
@property was proposed.
The idea was that functions marked with @property and the
correct number of parameters would work as property functions
and that they would _have_ to use the property syntax when
being used, whereas functions that weren't marked with
@property were not allowed to use the property syntax. The
ad-hoc nature of the whole thing then goes away, and stuff like
writeln = 42;
is then illegal. It also fixes the problem where the function
returns a callable (e.g. a delegate or a functor). If you have
the function foo, and it returns a callable, as long as it's
legal to call the function with the property syntax - foo - or
without - foo() - there's no way to distinguish when the
callable that's returned by the function should be called. If
foo is treated as a property, then foo() would call the
callable that foo returned, whereas if it's treated as a
function, then it would be foo()(). Without a way to indicate
that a function must be used as a property, there really isn't
a way to fix that.
However, introducing enforcement to @property was a major
breaking change. So, for a while the -property flag was
introduced which was supposed to add enforcement so that we
could get code working with it first and then switch over to it
being the normal behavior later. However, the -property switch
didn't fully implement all of the necessary checks, and a lot
of folks weren't using it, so the transitition really wasn't
happening. And then UFCS came along.
Once we got UFCS, it became normal to see code such as
auto foo = range.map!(a => bar + 42);
The first set of parens is for the template argument, so this
is technically using the property syntax. If @property were
enforced, then
auto foo = range.map!(a => bar + 42)();
would be required, and a lot of folks didn't like that. They
thought that it was too many parens. So, lots of folks didn't
want @property enforcement at that point. It really couldn't be
properly enabled without a lot of screaming, so plans do
enforce it were dropped as was the -property switch.
The result is that @property currently only really does two
things:
1. Make it so that typeof(foo) gives you the return type of the
function rather than the function's actual type (this can be
argued as a good or bad thing, but it was an attempt to make it
act the same as if foo were a variable, since properties are
supposed to try to emulate variables).
2. Restrict function overloads in that a function marked with
@property cannot be overloaded with one that's not marked with
@property.
@property does no sort of enforcement, and without enforcement,
it doesn't stop stuff like
writeln = 42;
It also doesn't affect functions that return callables, meaning
that you currently can't really have property functions that
return callables and have it work right.
@property has been in limbo ever since UFCS was added, and it
became _very_ popular to call functions without parens
regardless of whether they were really properties in the sense
that they acted like a variable. @property may be deprecated
eventually, or it may be that we get some sort of enforcement
for it that's specific to properties that are callables - e.g.
if it's used on a function returning a callable, then _it_ must
be called without parens to fix the ambiguity, but other
@property functions don't have that restriction. But the future
of @property is very much unknown at this point, and it simply
hasn't been a high enough priority to sort out.
However, @property _does_ get used heavily. It's _very_ common
practice to use it on property functions as documentation
(though I'm sure that since the spec hasn't been as clear on
the matter as it should be, plenty of folks use it thinking
that it's required). The reason to avoid it for those so
inclined is that if it's ever deprecated, then you'll have to
change your code, whereas if you don't use it, then you won't
have to change your code. But it may or may not ever be going
away. Either way, it's used so heavily in D code in general
(the standard library included), that it's not going to be
removed lightly.
Using @property clearly indicates to those using your code that
it was intended to be used as a property function, so that
arguably has value, but it's not going to enforce anything. The
key thing to take away as far as the style guide goes is that
you should use property functions rather than getters or
setters. Whether you use @property or not is up to you.
- Jonathan M Davis
That's a lot of detail. The bottom line is that the warning in
the spec is completely wrong and should be removed -- using
property functions is not discouraged, nor is @property.
@property should be used, both as documentation and because it
makes typeof work correctly. Maybe it will do even more later.