www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Getting consistent behavour for class properties

reply mikey <abc.mikey googlemail.com> writes:
Hi,

I'm experimenting with the behaviour of properties in D, as I am 
writing some classes that are being used in a mixture of const 
and non-const functions.

I've found a couple of things that I'd just like to check. First 
perhaps I should say what I would expect from working with 
properties in a mixed const / non-const environment.

* I expect getting a property to work for both const and 
non-const.
* I expect setting a property to only work for non-const.

I found that to get this behaviour I needed to declare any getter 
return type as well as the property function as "inout". This 
seemed to work for getter / setter function pairs as well as the 
" property auto ref" idiom.

I also noticed something that was unexpected to me as a beginner, 
that the getter / setter pairs are not valid with the "+=" 
operator but the "auto ref" is. I guess this is down to the way D 
interprets the syntax during compilation and the differences 
between how the 2 different implementations access the data. But 
it is none the less surprising that the flowing are not 
syntactically equivalent.

     t.val = t.val + 1;
     t.val += t.val;

Anyway here is my test code:

     module test;

     class Test {
     private:
         int _val;

     public:

          property inout(int) val() inout {
             return _val;
         }

          property void val(int val) {
             _val = val;
         }

          property auto ref inout(int) val2() inout {
             return _val;
         }
     }

     void test(Test t) {
         import std.stdio : writeln;
         writeln("--- test ----");
         writeln("val: ", t.val);
         writeln("val2: ", t.val2);
     }

     void test2(in Test t) {
         import std.stdio : writeln;
         writeln("--- test 2 ----");
         writeln("val: ", t.val);
         writeln("val2: ", t.val2);
     }

     void main() {

         auto t = new Test;
         //t.val += 100; // BAD - not an lvalue
         t.val = t.val + 100;
         test(t);
         t.val2 += 100; // OK
         test2(t);
     }
Oct 02 2016
next sibling parent mikey <abc.mikey googlemail.com> writes:
On Sunday, 2 October 2016 at 14:26:46 UTC, mikey wrote:
     t.val = t.val + 1;
     t.val += t.val;
Sorry that should have of course read: t.val = t.val + 1; t.val += 1;
Oct 02 2016
prev sibling next sibling parent reply Lodovico Giaretta <lodovico giaretart.net> writes:
On Sunday, 2 October 2016 at 14:26:46 UTC, mikey wrote:
 [...]
Yeah, a property is quite different from a variable. In fact, a property may refer to a computed value, which may not have an address and as such cannot be modified: property auto currentTimeMillis() { return currentTimeNanos/1000000; } So it is correct that `+=` doesn't work with properties, and neither does the "addressof" operator `&` (it returns the delegate). Having a getter property return by ref circumvents this issue, but has the drawback of bypassing any check that a setter property would do. If you want to use properties as getters/setters and also want compound assignments to work, you can easily achieve that with a wrapper template as this[1] one. [1] http://pastebin.com/38n0fEtF
Oct 02 2016
parent reply mikey <abc.mikey googlemail.com> writes:
On Sunday, 2 October 2016 at 14:44:13 UTC, Lodovico Giaretta 
wrote:
 Yeah, a property is quite different from a variable. In fact, a 
 property may refer to a computed value, which may not have an 
 address and as such cannot be modified:
 [...]
 So it is correct that `+=` doesn't work with properties, and 
 neither does the "addressof" operator `&` (it returns the 
 delegate). Having a getter property return by ref circumvents 
 this issue, but has the drawback of bypassing any check that a 
 setter property would do.
There is already a degree of transparency with how properties being handled for example in allowing properties to be an lvalue if they have a setter. t.val = 42; I can understand that on an implementation level it might be simpler to interpret the 2 statements differently but it would seem much more intuitive to me if the syntactic sugar for properties were extended out to allow statements such as: t.val += 1; Where there is a getter and setter available. To my mind at least the ideal would be for properties to act as close as possible to member variables. It is however good to see that it's possible to wrap functions to provide some of this behaviour.
Oct 02 2016
parent Lodovico Giaretta <lodovico giaretart.net> writes:
On Sunday, 2 October 2016 at 17:10:58 UTC, mikey wrote:
 There is already a degree of transparency with how properties 
 being handled for example in allowing properties to be an 
 lvalue if they have a setter.

     t.val = 42;
Actually, this is not specific to properties, as it also works on "standard" methods, if they have a single parameter: import std.stdio; void main() { writeln = 42; }
Oct 02 2016
prev sibling parent reply Kagamin <spam here.lot> writes:
I suppose that's https://issues.dlang.org/show_bug.cgi?id=8006
Oct 03 2016
parent mikey <abc.mikey googlemail.com> writes:
On Monday, 3 October 2016 at 14:05:24 UTC, Kagamin wrote:
 I suppose that's https://issues.dlang.org/show_bug.cgi?id=8006
Yes, exactly. Although, I don't see why they wrap it in a struct in the example as this seems to me to just obfuscate the issue.
Oct 09 2016