www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - equivalent of c++ private inheritance with using

reply "Dan" <dbdavidson yahoo.com> writes:
What is best way to get equivalent of C++ private inheritance 
combined with using declarations in the drived to expose some 
functionality. For example, suppose I want a basic RateCurve 
class that defers almost entirely to type Array as below. The 
problem is, once RateCurve is moved to a different module, the 
private impl prevents it from working:

Thanks
Dan

----------
module play.m.x;
import std.stdio;
import std.container;
import std.datetime;

struct DateValue {
    Date date;
    double value;
}

struct RateCurve {
   alias Array!DateValue Impl;
   alias impl this;

   // I am a Array!DateValue, so I can do:
   double getRate(Date d) {
     // access myself to get a rate...
     return 0;
   }

public: // If this is private it is a problem!!! How to fix?
   Impl impl;
}
----------
import std.stdio;
import std.datetime;
import play.m.x;

void main() {
   static if(0) {
     // Support for following would be great
     auto rc = RateCurve(DateValue(Date(2001,1,1), 0.2),
                         DateValue(Date(2002,1,1), 0.25));
   } else {
     auto rc = RateCurve();
   }
   rc.insert(DateValue(Date(2001,1,1), 0.2));
   // indexing
   writeln("Initial rate is ", rc[0]);
   auto someDate = Date(2001,6,1);
   auto rate = rc.getRate(someDate);
   foreach(r; rc) {
     writeln("on ", r.date, " rate is ", r.value);
   }
}
----------
Oct 12 2012
parent reply "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Friday, October 12, 2012 23:10:47 Dan wrote:
 What is best way to get equivalent of C++ private inheritance
 combined with using declarations in the drived to expose some
 functionality. For example, suppose I want a basic RateCurve
 class that defers almost entirely to type Array as below. The
 problem is, once RateCurve is moved to a different module, the
 private impl prevents it from working:
You can have the variable be private and alias a function which returns by ref instead of the variable itself. Something like class C { property ref inout(Impl) get() inout { return _impl; } alias get this; private: Impl _impl; } - Jonathan M Davis
Oct 12 2012
parent "Dan" <dbdavidson yahoo.com> writes:
On Friday, 12 October 2012 at 23:05:27 UTC, Jonathan M Davis 
wrote:

 You can have the variable be private and alias a function which 
 returns by ref
 instead of the variable itself. Something like

 class C
 {
   property ref inout(Impl) get() inout { return _impl; }
  alias get this;

 private:
  Impl _impl;
 }

 - Jonathan M Davis
Thanks, that is interesting, but is it the same? I don't think that this then provides any encapsulation? The idea is the client gets no access to Impl methods unless I say so and I say so with a using declaration. Then you can introduce more functionality, so it is implementation inheritance. It might not be possible to get the exact same thing, since the RateCurve struct is not really Array!DateValue, it just looks like it with the alias. The closest I can get is to alias each of what is needed and add forwarding functions. So, for example, with this new RateCurve, clients can call insert() but not call clear(). struct RateCurve { alias Array!DateRate ContainerType; alias ContainerType.Range Range; alias _impl this; size_t insert(Stuff)(Stuff stuff) { enforce(_impl.empty || (stuff.when >= _impl.back.when), text("Can not insert items out of order ", _impl.back, " is newer than ", stuff)); return _impl.insert(stuff); } DateRate getRate(Date asOf) { auto needle = DateRate(asOf, 0); if(!_impl.empty) { auto sortedRage = assumeSorted!("a.when <= b.when", Range)(opSlice()); auto lowerBound = sortedRage.lowerBound(needle); if(!lowerBound.empty) { needle = lowerBound.back; } } return needle; } Range opSlice() { return _impl.opSlice(); } this(U)(U[] values...) if (isImplicitlyConvertible!(U, DateRate)) { foreach (value; values) { insert(value); } } private: ContainerType _impl; }
Oct 14 2012