February 07, 2013 Re: DIP23 Counter Proposal | ||||
---|---|---|---|---|
| ||||
Posted in reply to Steven Schveighoffer | On Thu, 07 Feb 2013 15:02:41 -0000, Steven Schveighoffer <schveiguy@yahoo.com> wrote: > On Wed, 06 Feb 2013 23:26:03 -0500, Chad Joan <chadjoan@gmail.com> wrote: > >> On 02/05/2013 09:45 PM, Steven Schveighoffer wrote: >>> ... >>> >>> The semantic rewrite stuff is something I don't feel strongly either >>> way. It would be nice, but at the same time, it doesn't feel necessary >>> to me. One can always simply avoid it by not using the operators on >>> properties. >>> >> >> A core feature of properties is that variables can be migrated to them (and back) without breaking any of the caller's code. Forbidding more than half of D's operators on them will definitely break this attribute. > > I find this explanation lacking. A field supports operations that are impossible to implement with properties, there will never be a non-code-breaking change from a field to a property. So it's a matter of "how much" breakage you want to allow. This is really a judgment call, there is no "right" answer. The closest you can get to a field is to ref an actual field. But in that case, I don't see the point of the property, since you give unfettered access to the field! > > The whole point of having properties that I see is to implement things you CAN'T implement with a field, or are more cumbersome. Like read-only fields. Such a change would necessarily and on purpose break code. There are several "points" to properties it would seem: http://en.wikipedia.org/wiki/Property_(programming) I have heard the goal Chad mentions said numerous times in similar discussions (to allow migration of fields to properties and back without breaking caller code) and I imagine this would be true and work in all cases for languages which don't have pointers, perhaps. But as D has pointers there can and probably does exist caller code which takes the address of a public field and would therefore simply break if that field was changed into a "property" (AKA method call). Now, perhaps there is some magic the compiler could do to make it work again, but if to achieve this we really have to jump through some crazy hoops or add complexity and edge-cases to the language then it's just not worth it, IMO. And, as Steven has said implementing read-only fields and adding layers of functionality are 2 other goals/points of properties and these are certainly useful by themselves, with or without any other benefits. R -- Using Opera's revolutionary email client: http://www.opera.com/mail/ |
February 07, 2013 Re: DIP23 Counter Proposal | ||||
---|---|---|---|---|
| ||||
Posted in reply to Steven Schveighoffer | On Thursday, February 07, 2013 10:02:41 Steven Schveighoffer wrote:
> On Wed, 06 Feb 2013 23:26:03 -0500, Chad Joan <chadjoan@gmail.com> wrote:
> > On 02/05/2013 09:45 PM, Steven Schveighoffer wrote:
> >> ...
> >>
> >> The semantic rewrite stuff is something I don't feel strongly either way. It would be nice, but at the same time, it doesn't feel necessary to me. One can always simply avoid it by not using the operators on properties.
> >
> > A core feature of properties is that variables can be migrated to them (and back) without breaking any of the caller's code. Forbidding more than half of D's operators on them will definitely break this attribute.
>
> I find this explanation lacking. A field supports operations that are impossible to implement with properties, there will never be a non-code-breaking change from a field to a property. So it's a matter of "how much" breakage you want to allow. This is really a judgment call, there is no "right" answer. The closest you can get to a field is to ref an actual field. But in that case, I don't see the point of the property, since you give unfettered access to the field!
>
> The whole point of having properties that I see is to implement things you CAN'T implement with a field, or are more cumbersome. Like read-only fields. Such a change would necessarily and on purpose break code.
It works as long as you can limit the variable in some way. But I believe that the main purpose in using public variables rather than actual property functions when all they would do is get or set the variable is to avoid lots of boilerplate code. It's incredibly common to get stuff like
struct S
{
int i() @safe const pure nothrow
{ return _i; }
int i(int value) @safe pure nothrow
{ return _i = value; }
private int _i;
}
That's a lot of extra code whose only benefit is encapsulation. So, it would be great if you could just do
struct S
{
int i;
}
And with the ability to replace the variable with a property function later if it ever needs to do more than just get or set makes it so that encapsulation isn't a problem - except for the fact that there are certain operations that you can do on a variable that you can't do on a property function (e.g. taking its address or passing it by ref). Simply making it so that doing
struct S
{
@property int i;
}
lowered into something like the first example would allow you to avoid all of that boilerplate code and still have full encapsulation.
It's definitely true that you can never make a property function completely emulate a variable, but all of the boilerplate required for simple getters and setters is kind of ridiculous. I believe that avoiding that is the primary reason that people want to be able to swap between variables and property functions, and with a small addition to the language, we can obviate that boilerplate.
- Jonathan M Davis
|
February 07, 2013 Re: DIP23 Counter Proposal | ||||
---|---|---|---|---|
| ||||
Posted in reply to Jonathan M Davis | On Thursday, 7 February 2013 at 20:26:10 UTC, Jonathan M Davis wrote: > It works as long as you can limit the variable in some way. But I believe that > the main purpose in using public variables rather than actual property > functions when all they would do is get or set the variable is to avoid lots > of boilerplate code. It's incredibly common to get stuff like > > struct S > { > int i() @safe const pure nothrow > { return _i; } > > int i(int value) @safe pure nothrow > { return _i = value; } > > private int _i; > } > > That's a lot of extra code whose only benefit is encapsulation. So, it would be > great if you could just do > > struct S > { > int i; > } > > And with the ability to replace the variable with a property function later if > it ever needs to do more than just get or set makes it so that encapsulation > isn't a problem - except for the fact that there are certain operations that > you can do on a variable that you can't do on a property function (e.g. taking > its address or passing it by ref). Simply making it so that doing > > struct S > { > @property int i; > } > > lowered into something like the first example would allow you to avoid all of > that boilerplate code and still have full encapsulation. If it lowered into something like the first example would there really be any encapsulation? Wouldn't that be exactly the same as public int i? If this is the goal - to get rid of the boilerplate of accessors, it makes sense but a new feature is not necessary. If you want read/write access to a member but the benefit of being able to intercept access in the future start with struct S { int i; }. When the need arises to change the behavior, switch to: struct S { int i() @safe const pure nothrow { // SPECIAL SAUCE return _i; } int i(int value) @safe pure nothrow { // SPECIAL SAUCE return _i = value; } private int _i; } If you don't have any SPECIAL SAUCE then you don't need to switch. If you want more encapsulation and specifically don't want to provide write access, just read access then a mixin can do the trick of providing read access to s.i. In the future you can change the read accessor and provide one with SPECIAL SAUCE. struct S { mixin ReadOnly!_i; private int _i; } > > It's definitely true that you can never make a property function completely > emulate a variable, but all of the boilerplate required for simple getters and > setters is kind of ridiculous. I believe that avoiding that is the primary > reason that people want to be able to swap between variables and property > functions, and with a small addition to the language, we can obviate that > boilerplate. > No addition needed. Thanks Dan |
February 07, 2013 Re: DIP23 Counter Proposal | ||||
---|---|---|---|---|
| ||||
Posted in reply to Dan | > > struct S
> > {
> > @property int i;
> > }
> >
You missed the point. When this gets lowered to accessor functions and a private variable, you ensure that you can later on add your magic soup, without breaking code that relied on i being a real field. (E.g. taking the address, using +=, -=, ...)
Although += or -= can still be added for properties, but the important thing is, that for an @property declared field nothing is possible, that is not also possible with a property created by manually writing set/get methods.
|
February 07, 2013 Re: DIP23 Counter Proposal | ||||
---|---|---|---|---|
| ||||
Posted in reply to Jonathan M Davis | On Thu, 07 Feb 2013 15:25:57 -0500, Jonathan M Davis <jmdavisProg@gmx.com> wrote: > struct S > { > @property int i; > } struct S { mixin(boilerplateProperty("i")); } I don't see this as a difficult problem to solve. -Steve |
February 07, 2013 Re: DIP23 Counter Proposal | ||||
---|---|---|---|---|
| ||||
Posted in reply to Steven Schveighoffer | On Thursday, 7 February 2013 at 21:12:35 UTC, Steven Schveighoffer wrote:
> struct S
> {
> mixin(boilerplateProperty("i"));
> }
>
> I don't see this as a difficult problem to solve.
>
> -Steve
+1
|
February 07, 2013 Re: DIP23 Counter Proposal | ||||
---|---|---|---|---|
| ||||
Posted in reply to Jonathan M Davis | In C#, they have introduced automatic properties for that purpose of "initial encapsulation":
public int i { get; set; } //get and set can be modified with private etc
Then the getter and setter methods are automatically implemented.
I'm not closely following the discussions involved in the re-design of properties, but I disagree with the people that believe properties are glorified fields. IMO, they are essentially functions, accessed like fields, that can set and/or expose state. I'm also against 2-parametrized properties btw.
Example: define a interface for geometric figures with a "area" property and then implement it for square, circle, hexagon, triangle etc
On Thursday, 7 February 2013 at 20:26:10 UTC, Jonathan M Davis wrote:
> It works as long as you can limit the variable in some way. But I believe that
> the main purpose in using public variables rather than actual property
> functions when all they would do is get or set the variable is to avoid lots
> of boilerplate code. It's incredibly common to get stuff like
>
> struct S
> {
> int i() @safe const pure nothrow
> { return _i; }
>
> int i(int value) @safe pure nothrow
> { return _i = value; }
>
> private int _i;
> }
>
> That's a lot of extra code whose only benefit is encapsulation. So, it would be
> great if you could just do
>
> struct S
> {
> int i;
> }
>
> And with the ability to replace the variable with a property function later if
> it ever needs to do more than just get or set makes it so that encapsulation
> isn't a problem - except for the fact that there are certain operations that
> you can do on a variable that you can't do on a property function (e.g. taking
> its address or passing it by ref). Simply making it so that doing
>
> struct S
> {
> @property int i;
> }
>
> lowered into something like the first example would allow you to avoid all of
> that boilerplate code and still have full encapsulation.
>
> It's definitely true that you can never make a property function completely
> emulate a variable, but all of the boilerplate required for simple getters and
> setters is kind of ridiculous. I believe that avoiding that is the primary
> reason that people want to be able to swap between variables and property
> functions, and with a small addition to the language, we can obviate that
> boilerplate.
>
> - Jonathan M Davis
|
February 07, 2013 Re: DIP23 Counter Proposal | ||||
---|---|---|---|---|
| ||||
Posted in reply to Robert | On Thursday, 7 February 2013 at 21:05:49 UTC, Robert wrote:
> You missed the point. When this gets lowered to accessor functions and a
> private variable, you ensure that you can later on add your magic soup,
> without breaking code that relied on i being a real field. (E.g. taking
> the address, using +=, -=, ...)
Quite likely I missed the point.
Today I have:
struct S
{
@property int i;
}
Tomorrow I decide I need to track every time int i is read and written.
How is that done?
I assume that that sort of encapsulation is what we are after.
Thanks
Dan
|
February 07, 2013 Re: DIP23 Counter Proposal | ||||
---|---|---|---|---|
| ||||
Posted in reply to Steven Schveighoffer | On Thursday, February 07, 2013 16:12:34 Steven Schveighoffer wrote:
> On Thu, 07 Feb 2013 15:25:57 -0500, Jonathan M Davis <jmdavisProg@gmx.com>
>
> wrote:
> > struct S
> > {
> >
> > @property int i;
> >
> > }
>
> struct S
> {
> mixin(boilerplateProperty("i"));
> }
>
> I don't see this as a difficult problem to solve.
Except that mixins are generally unacceptable in APIs, because they don't end up in the documentation. That means that this works only if you don't care about documentation. So, it's almost useless. Putting @property on there also looks better but isn't that big a deal. However, the lack of documentation _is_ a big deal.
- Jonathan M Davis
|
February 07, 2013 Re: DIP23 Counter Proposal | ||||
---|---|---|---|---|
| ||||
Posted in reply to Steven Schveighoffer | I am not completely against this, but it feels quite artificial to make a builtin feature complete this way. If we implement the property stuff completely via library methods, I would like it more, but if it is documented properly, might not be too bad:
struct S {
mixin(property(int, "i"));
}
On Thu, 2013-02-07 at 16:12 -0500, Steven Schveighoffer wrote:
> struct S
> {
> mixin(boilerplateProperty("i"));
> }
|
Copyright © 1999-2021 by the D Language Foundation