www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Are properties mature enough?

reply QueenSvetlana <svetlanalilyrosemond gmail.com> writes:
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?
Aug 19 2018
next sibling parent reply Neia Neutuladh <neia ikeran.org> writes:
On Sunday, 19 August 2018 at 18:32:17 UTC, QueenSvetlana 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?
The ` property` annotation might not remain in the language. However, the property call syntax for functions will remain. So you can write: --- struct Random { private int value; int next() { value++; return value; } void seed(int value) { this.value = value; } } Random r; r.seed = 21; writeln(r.next); --- That's going to work forever. You *could* add property to the next and seed functions. That forces people to use them as fields. However, there's some discussion about how that's going to be handled in the future. So you might want to leave it off.
Aug 19 2018
parent ag0aep6g <anonymous example.com> writes:
On 08/19/2018 08:55 PM, Neia Neutuladh wrote:
 You *could* add  property to the next and seed functions. That forces 
 people to use them as fields.
It doesn't.
Aug 19 2018
prev sibling parent reply Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
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
Aug 19 2018
parent reply Jim Balter <Jim Balter.name> writes:
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.
Aug 21 2018
parent Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Tuesday, August 21, 2018 1:46:31 PM MDT Jim Balter via Digitalmars-d-
learn wrote:
 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.
Whether it makes typeof work correctly is a matter of debate. It makes it act more like a varable, which is in line with the property function acting like a variable. However, it isn't actually a variable, and aside from calling the function without parens or being able to assign to it, it really doesn't act like a variable. So, having typeof claim that it is actually tends to cause problems when doing metaprogramming. Also, because property isn't required to get the property syntax, what typeof says really doesn't have much to do with what's syntactically valid. What usually makes more sense is to check the type of expressions using the symbol rather than directly checking the type of the symbol. So, while property serves as a good way to indicate the intent of the API author, all it really does beyond that is cause problems with metaprogramming. So, while I definitely use it, I'd honestly argue that the fact that typeof lies about what the actual type is when property is used is a serious problem. - Jonathan M Davis
Aug 21 2018