www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - property syntax problems

reply Alex Burton <alexibu mac.com> writes:
Hi,

I just found a bug that comes out of the property syntax.

The property syntax is great in that it allows a smooth transition from simple
code dealing with public member variables to the use of interfaces without
needing to update the client code.
i.e. A.bob = 1 can stay as A.bob = 1 when bob changes from being an int to
being void A::bob(int i)
instead of changing to A.bob(1).

But this can introduce the bug I show below.

Proposal :
If the temporary returned by the property syntax getter function is modified,
then the corresponding setter function needs to be called with the temporary as
argument.

struct A
{
      int i;
      int j;
};

class B
{
  A mA;
public:
	A a() { return mA; }
	void a(Atom a) { mA = a; }
};


int main()
{
     B b;
     b.a.j = 10;     // error b.a is a temporary.
}
Feb 05 2009
next sibling parent reply "Robert Jacques" <sandford jhu.edu> writes:
On Thu, 05 Feb 2009 06:55:46 -0500, Alex Burton <alexibu mac.com> wrote:

 Hi,

 I just found a bug that comes out of the property syntax.

 The property syntax is great in that it allows a smooth transition from  
 simple code dealing with public member variables to the use of  
 interfaces without needing to update the client code.
 i.e. A.bob = 1 can stay as A.bob = 1 when bob changes from being an int  
 to being void A::bob(int i)
 instead of changing to A.bob(1).

 But this can introduce the bug I show below.

 Proposal :
 If the temporary returned by the property syntax getter function is  
 modified, then the corresponding setter function needs to be called with  
 the temporary as argument.

 struct A
 {
       int i;
       int j;
 };

 class B
 {
   A mA;
 public:
 	A a() { return mA; }
 	void a(Atom a) { mA = a; }
 };


 int main()
 {
      B b;
      b.a.j = 10;     // error b.a is a temporary.
 }
This isn't a bug, it's a feature. What you wanted to use were ref returns (see http://www.digitalmars.com/d/2.0/function.html ) ref A a() { return mA; }
Feb 05 2009
parent reply Bill Baxter <wbaxter gmail.com> writes:
On Fri, Feb 6, 2009 at 2:34 AM, Robert Jacques <sandford jhu.edu> wrote:
 On Thu, 05 Feb 2009 06:55:46 -0500, Alex Burton <alexibu mac.com> wrote:

 Hi,

 I just found a bug that comes out of the property syntax.

 The property syntax is great in that it allows a smooth transition from
 simple code dealing with public member variables to the use of interfaces
 without needing to update the client code.
 i.e. A.bob = 1 can stay as A.bob = 1 when bob changes from being an int to
 being void A::bob(int i)
 instead of changing to A.bob(1).

 But this can introduce the bug I show below.

 Proposal :
 If the temporary returned by the property syntax getter function is
 modified, then the corresponding setter function needs to be called with the
 temporary as argument.

 struct A
 {
      int i;
      int j;
 };

 class B
 {
  A mA;
 public:
        A a() { return mA; }
        void a(Atom a) { mA = a; }
 };


 int main()
 {
     B b;
     b.a.j = 10;     // error b.a is a temporary.
 }
This isn't a bug, it's a feature. What you wanted to use were ref returns (see http://www.digitalmars.com/d/2.0/function.html ) ref A a() { return mA; }
You could call it a bug that the compiler doesn't warn about the modification of a temporary like that in a way that has no side effects. Or maybe it does warn about it if you enable warnings? --bb
Feb 05 2009
parent reply "Robert Jacques" <sandford jhu.edu> writes:
On Thu, 05 Feb 2009 14:27:27 -0500, Bill Baxter <wbaxter gmail.com> wrote:

 On Fri, Feb 6, 2009 at 2:34 AM, Robert Jacques <sandford jhu.edu> wrote:
 On Thu, 05 Feb 2009 06:55:46 -0500, Alex Burton <alexibu mac.com> wrote:
 int main()
 {
     B b;
     b.a.j = 10;     // error b.a is a temporary.
 }
This isn't a bug, it's a feature. What you wanted to use were ref returns (see http://www.digitalmars.com/d/2.0/function.html ) ref A a() { return mA; }
You could call it a bug that the compiler doesn't warn about the modification of a temporary like that in a way that has no side effects. Or maybe it does warn about it if you enable warnings? --bb
Actually, from that point of view
 b.a.j = 10;     // error b.a is a temporary.
isn't the real ( or I think desired ) warning. The real issue is that b.a.j results in an unused variable which several other compilers issue warnings about and is a much more general issue.
Feb 05 2009
parent Alex Burton <alexibu mac.com> writes:
Robert Jacques Wrote:

 On Thu, 05 Feb 2009 14:27:27 -0500, Bill Baxter <wbaxter gmail.com> wrote:
 
 On Fri, Feb 6, 2009 at 2:34 AM, Robert Jacques <sandford jhu.edu> wrote:
 On Thu, 05 Feb 2009 06:55:46 -0500, Alex Burton <alexibu mac.com> wrote:
 int main()
 {
     B b;
     b.a.j = 10;     // error b.a is a temporary.
 }
This isn't a bug, it's a feature. What you wanted to use were ref returns (see http://www.digitalmars.com/d/2.0/function.html ) ref A a() { return mA; }
You could call it a bug that the compiler doesn't warn about the modification of a temporary like that in a way that has no side effects. Or maybe it does warn about it if you enable warnings? --bb
Actually, from that point of view
 b.a.j = 10;     // error b.a is a temporary.
isn't the real ( or I think desired ) warning. The real issue is that b.a.j results in an unused variable which several other compilers issue warnings about and is a much more general issue.
I think in this case it has to be an error, precicely because the syntax doesn't show that there is a function call. If I do this: x.variable() = 7; Then I can expect it to do nothing as the parentheses show that this is a function. If I do this: x.variable = 7; I expect the code to work as intended which means that : writefln("x.variable = %d",x.variable); should print "x.variable = 7" And this does work as long as variable is a plain old data. The problem occurs when variable is a struct or class. Which allows me to type : x.variable.i = 7 Which doesn't work as expected. Moreover code evolving from variable being an int to a struct with two ints is common. Alex
Feb 05 2009
prev sibling next sibling parent reply Alex Burton <alexibu mac.com> writes:
Robert Jacques Wrote:

 On Thu, 05 Feb 2009 06:55:46 -0500, Alex Burton <alexibu mac.com> wrote:
 
 Hi,

 I just found a bug that comes out of the property syntax.

 The property syntax is great in that it allows a smooth transition from  
 simple code dealing with public member variables to the use of  
 interfaces without needing to update the client code.
 i.e. A.bob = 1 can stay as A.bob = 1 when bob changes from being an int  
 to being void A::bob(int i)
 instead of changing to A.bob(1).

 But this can introduce the bug I show below.

 Proposal :
 If the temporary returned by the property syntax getter function is  
 modified, then the corresponding setter function needs to be called with  
 the temporary as argument.

 struct A
 {
       int i;
       int j;
 };

 class B
 {
   A mA;
 public:
 	A a() { return mA; }
 	void a(A a) { mA = a; }
 };


 int main()
 {
      B b;
      b.a.j = 10;     // error b.a is a temporary.
 }
This isn't a bug, it's a feature. What you wanted to use were ref returns (see http://www.digitalmars.com/d/2.0/function.html ) ref A a() { return mA; }
Using ref A a() { return mA; } requires us to have a member variable mA ( which is actually there in the example). One of the reasons for using the setter and getter functions instead of the raw member variable is that there is not actually a member variable. For example: A a() { Dataset ds = mDatabase.Execute("SELECT A,B FROM TABLE"); return A(ds[0][0],ds[0][1]); } void a(A a) { mDatabase.Execute(format("INSERT %d,%d INTO TABLE;",a.i,a.j)); } The only way I can see to handle this correctly is to use my proposal above. This could be a really valuable feature in D if correctly implemented. Being able to transparently change from a member variable in a struct to getters and setters on a struct to getters and setters on a class and in reverse order is really powerful and allows code to evolve in a much more fluid way. Alex
Feb 05 2009
parent reply "Robert Jacques" <sandford jhu.edu> writes:
On Thu, 05 Feb 2009 20:26:03 -0500, Alex Burton <alexibu mac.com> wrote:

 Robert Jacques Wrote:

 On Thu, 05 Feb 2009 06:55:46 -0500, Alex Burton <alexibu mac.com> wrote:

 Hi,

 I just found a bug that comes out of the property syntax.

 The property syntax is great in that it allows a smooth transition  
from
 simple code dealing with public member variables to the use of
 interfaces without needing to update the client code.
 i.e. A.bob = 1 can stay as A.bob = 1 when bob changes from being an  
int
 to being void A::bob(int i)
 instead of changing to A.bob(1).

 But this can introduce the bug I show below.

 Proposal :
 If the temporary returned by the property syntax getter function is
 modified, then the corresponding setter function needs to be called  
with
 the temporary as argument.

 struct A
 {
       int i;
       int j;
 };

 class B
 {
   A mA;
 public:
 	A a() { return mA; }
 	void a(A a) { mA = a; }
 };


 int main()
 {
      B b;
      b.a.j = 10;     // error b.a is a temporary.
 }
This isn't a bug, it's a feature. What you wanted to use were ref returns (see http://www.digitalmars.com/d/2.0/function.html ) ref A a() { return mA; }
Using ref A a() { return mA; } requires us to have a member variable mA ( which is actually there in the example). One of the reasons for using the setter and getter functions instead of the raw member variable is that there is not actually a member variable. For example: A a() { Dataset ds = mDatabase.Execute("SELECT A,B FROM TABLE"); return A(ds[0][0],ds[0][1]); } void a(A a) { mDatabase.Execute(format("INSERT %d,%d INTO TABLE;",a.i,a.j)); } The only way I can see to handle this correctly is to use my proposal above. This could be a really valuable feature in D if correctly implemented. Being able to transparently change from a member variable in a struct to getters and setters on a struct to getters and setters on a class and in reverse order is really powerful and allows code to evolve in a much more fluid way. Alex
Alex, this looks like you want to use proxy structs/objects. Remember each of the following are equivalent: b.a.j = 10; <=> (b.a).j = 10; <=> auto c = b.a; c.j = 10; And that last case is a kinda tricky. Also, the x.y.z = 10 not doing anything when y is a struct from your other post is a well known issue is all languages that have POD struct (As far as I know). The solution is to move x.y to a ref return property. Moving from POD members to functions in order to support more complex logic is the primary motivation of properties.
Feb 05 2009
parent Christopher Wright <dhasenan gmail.com> writes:
Robert Jacques wrote:
 Also, the x.y.z = 10 not doing anything when y is a struct from your 
 other post is a well known issue is all languages that have POD struct 
 (As far as I know). The solution is to move x.y to a ref return 
 property. Moving from POD members to functions in order to support more 
 complex logic is the primary motivation of properties.
in my company's product (anything that is difficult to initialize with all the proper fields) is a class, and anything remaining that is a struct has only read-only properties.
Feb 06 2009
prev sibling parent reply Chad J <gamerchad __spam.is.bad__gmail.com> writes:
Alex Burton wrote:
 Hi,
 
 I just found a bug that comes out of the property syntax.
 
Yep, as was said, this is a "feature". Sadly I forget why, but I'm pretty sure ref returning doesn't solve all of the problems with properties, just this one (sorta). Also, D1 doesn't have ref returns, so if you're using D1 you're just plain outta' luck. This has been griped about for a few years now. There are also other serious shortcomings of the syntax. (Sorry, I'm too lazy to look up the old threads right now.) Given the "ref returns and properties" thread and a couple other posts that Andrei made, I suspect this is receiving some thought.
Feb 05 2009
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Chad J wrote:
 Alex Burton wrote:
 Hi,

 I just found a bug that comes out of the property syntax.
Yep, as was said, this is a "feature". Sadly I forget why, but I'm pretty sure ref returning doesn't solve all of the problems with properties, just this one (sorta). Also, D1 doesn't have ref returns, so if you're using D1 you're just plain outta' luck. This has been griped about for a few years now. There are also other serious shortcomings of the syntax. (Sorry, I'm too lazy to look up the old threads right now.) Given the "ref returns and properties" thread and a couple other posts that Andrei made, I suspect this is receiving some thought.
Yah, I gotta say that the a.b.c = d catastrophe finally dropped the coin for me. Andrei
Feb 05 2009