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