www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Easy way to implement interface properties?

reply "Frustrated" <c1514843 drdrb.com> writes:
Is there an easy way to implement properties of an interface 
within a class instead of having to duplicate almost the exact 
same code with generic properties?

interface A
{
      property int data();
      property int data(int value);

}

class B : A
{
    property int data() { return m_data; } // read property
    property int data(int value) { return m_data = value; } // 
write property
}

lots of duplicate info, specially when there are a lot of 
properties, and changing anything in the interface requires 
changing it in the class.

Instead I'd like to do something like

class B : A
{
     ....

     implement!A;
}

where implement!A implements all the properties and functions in 
A that are not already defined in B using simple methods(just 
returning default values for functions and wrapping a field for 
properties).

This way I can design the structural aspect of the software 
without having to worry about implementation but still do some 
basic testing. I can also slowly build up the functionality of 
the code by implementing properties and functions without having 
to worry about an all or nothing approach(or having to worry 
about the original problem of code duplication).
Dec 31 2013
next sibling parent reply "Adam D. Ruppe" <destructionator gmail.com> writes:
On Wednesday, 1 January 2014 at 00:52:24 UTC, Frustrated wrote:
    property int data() { return m_data; } // read property
    property int data(int value) { return m_data = value; } // 
 write property
Put that stuff in a mixin template. interface A { property int data(); property int data(int value); } mixin template A_Impl() { private int m_data; property int data() { return m_data; } property int data(int value) { return m_data = value; } } class B : A { mixin A_Impl!(); }
 where implement!A implements all the properties and functions 
 in A that are not already defined in B using simple methods
The mixin template handles this too: class B : A { mixin A_Impl!(); property int data() { return m_data; } property int data(int value) { return m_data = value; } } There, it uses the property from the mixin, but B defines its own property implementations. Something explicitly written in the class definition overrides the item with the same name from the mixin. Here, this looks silly, but if you had several properties in the mixin template, you could selectively customize just one while reusing the others. Note however that overloads don't cross this. So if class B only implemented the getter, it would complain that the setter isn't there: defining one function called "data" meant it didn't bring in *any* "data" methods from the mixin. But all the others would still be there. This interface + impl mixin template is also how I'd recommend doing multiple inheritance in D, you just do this same deal for each one.
Dec 31 2013
parent reply "Frustrated" <c1514843 drdrb.com> writes:
On Wednesday, 1 January 2014 at 01:22:27 UTC, Adam D. Ruppe wrote:
 On Wednesday, 1 January 2014 at 00:52:24 UTC, Frustrated wrote:
   property int data() { return m_data; } // read property
   property int data(int value) { return m_data = value; } // 
 write property
Put that stuff in a mixin template. interface A { property int data(); property int data(int value); } mixin template A_Impl() { private int m_data; property int data() { return m_data; } property int data(int value) { return m_data = value; } } class B : A { mixin A_Impl!(); }
 where implement!A implements all the properties and functions 
 in A that are not already defined in B using simple methods
The mixin template handles this too: class B : A { mixin A_Impl!(); property int data() { return m_data; } property int data(int value) { return m_data = value; } } There, it uses the property from the mixin, but B defines its own property implementations. Something explicitly written in the class definition overrides the item with the same name from the mixin. Here, this looks silly, but if you had several properties in the mixin template, you could selectively customize just one while reusing the others. Note however that overloads don't cross this. So if class B only implemented the getter, it would complain that the setter isn't there: defining one function called "data" meant it didn't bring in *any* "data" methods from the mixin. But all the others would still be there. This interface + impl mixin template is also how I'd recommend doing multiple inheritance in D, you just do this same deal for each one.
But your template mixin is still duplicating generic code that should be easily handled automatically. (Generic properties are just wrappers around private fields that always have the same code (just return or set the field)) I'd like to avoid that. Whether using a template mixin or not(which solve the 2nd part of the problem) is there a way to generate code for the interface automatically? This would require compile time reflection(knowing the names, fields, properties, functions, etc...) of the interface then generating the code(as a string mixin I guess).
Dec 31 2013
parent reply "Adam D. Ruppe" <destructionator gmail.com> writes:
On Wednesday, 1 January 2014 at 01:33:04 UTC, Frustrated wrote:
 But your template mixin is still duplicating generic code that 
 should be easily handled automatically. (Generic properties are 
 just wrappers around private fields that always have the same 
 code (just return or set the field))
Oh yeah, that can be done too. Here's an example: http://arsdnet.net/dcode/autoimpl.d The mixin template is implemented by a helper function, which loops over the interface methods and builds a code string for it. It doesn't handle complex cases, like a setter without a getter, but it is a start. The pragma(msg) in there shows you the generated code when it compiles, which can help debugging or just show you what's going on, of course you can remove that when you're happy with it.
Dec 31 2013
next sibling parent "Frustrated" <c1514843 drdrb.com> writes:
On Wednesday, 1 January 2014 at 01:55:19 UTC, Adam D. Ruppe wrote:
 On Wednesday, 1 January 2014 at 01:33:04 UTC, Frustrated wrote:
 But your template mixin is still duplicating generic code that 
 should be easily handled automatically. (Generic properties 
 are just wrappers around private fields that always have the 
 same code (just return or set the field))
Oh yeah, that can be done too. Here's an example: http://arsdnet.net/dcode/autoimpl.d The mixin template is implemented by a helper function, which loops over the interface methods and builds a code string for it. It doesn't handle complex cases, like a setter without a getter, but it is a start. The pragma(msg) in there shows you the generated code when it compiles, which can help debugging or just show you what's going on, of course you can remove that when you're happy with it.
This doesn't quite work(at least for me) and seems unstable. Doesn't get all the attributes(what if you have a safe property? And doesn't get methods. It is a start though....
Dec 31 2013
prev sibling parent "Frustrated" <c1514843 drdrb.com> writes:
By modifying the code I was able to achieve exactly what I 
wanted(I have very complex interfaces but the classes using them 
consist of just one line.

The code basically fixes your code to handle the setter and 
getters better and to work with functions. It is not very robust 
so I won't post it hoping someone will come up with something 
better.
Dec 31 2013
prev sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2014-01-01 01:52, Frustrated wrote:
 Is there an easy way to implement properties of an interface within a
 class instead of having to duplicate almost the exact same code with
 generic properties?

 interface A
 {
       property int data();
       property int data(int value);

 }

 class B : A
 {
     property int data() { return m_data; } // read property
     property int data(int value) { return m_data = value; } // write
 property
 }
You can't use an abstract class? -- /Jacob Carlborg
Jan 01 2014
parent reply "Gary Willoughby" <dev nomad.so> writes:
On Wednesday, 1 January 2014 at 12:09:40 UTC, Jacob Carlborg 
wrote:
 On 2014-01-01 01:52, Frustrated wrote:
 Is there an easy way to implement properties of an interface 
 within a
 class instead of having to duplicate almost the exact same 
 code with
 generic properties?

 interface A
 {
      property int data();
      property int data(int value);

 }

 class B : A
 {
    property int data() { return m_data; } // read property
    property int data(int value) { return m_data = value; } // 
 write
 property
 }
You can't use an abstract class?
Yes this is the ideal time to use an abstract base class and is what i would do. The same thing *could* be achieved using mixin templates, with or without scopes but could lead to unmaintainable code. See the examples on mixin templates here: http://nomad.so/2013/07/templates-in-d-explained/
Jan 01 2014
parent "Frustrated" <c1514843 drdrb.com> writes:
On Wednesday, 1 January 2014 at 14:30:46 UTC, Gary Willoughby 
wrote:
 On Wednesday, 1 January 2014 at 12:09:40 UTC, Jacob Carlborg 
 wrote:
 On 2014-01-01 01:52, Frustrated wrote:
 Is there an easy way to implement properties of an interface 
 within a
 class instead of having to duplicate almost the exact same 
 code with
 generic properties?

 interface A
 {
     property int data();
     property int data(int value);

 }

 class B : A
 {
   property int data() { return m_data; } // read property
   property int data(int value) { return m_data = value; } // 
 write
 property
 }
You can't use an abstract class?
Yes this is the ideal time to use an abstract base class and is what i would do. The same thing *could* be achieved using mixin templates, with or without scopes but could lead to unmaintainable code. See the examples on mixin templates here: http://nomad.so/2013/07/templates-in-d-explained/
With abstract classes I would still have to implement generic code and it would not be much different than using a standard class(The inheritance is only about 2 levels deep but many interfaces). I don't see how the mixin method would be unmaintainable since it simply implements what hasn't been implemented(it could lead to bugs if one forgets to implement stuff but that's easy to check(functions could throw exceptions in "retail" build)). Basically Adam's approach is what I was looking for as I see it as the best way unless you have any specific reasons why it doesn't work well. (of course the interface implementer isn't robust but I'm working on that)
Jan 01 2014