Are properties mature enough?
Jim Balter
Jim at Balter.name
Tue Aug 21 19:46:31 UTC 2018
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.
More information about the Digitalmars-d-learn
mailing list