Topic: A proposal for a new kind of inheritance called "using" inheritance


Author: ros0230@iperbole.bologna.it (Natale Fietta)
Date: Fri, 13 Sep 2002 16:31:35 +0000 (UTC)
Raw View
On Wed, 11 Sep 2002 18:30:34 +0000 (UTC), Attila.Feher@lmf.ericsson.se
(Attila Feher) wrote:

>Looks interesing.  However I could not say just now what are the
>implications.  I have found many times, that such designs, which require
>these kind of missing language constracts are flawed in some way...
>Please read me reply to Steve Heller, where I elaborate on why do I
>think that dragging in a whole public interface in the Implemented-Using
>case seems to be a fundamentally bad idea.

I have read it, i understand the reasoning but disagree with your
conclusions, for me the fact that Full Interface Republication (FIR
from now on, i am a lazy typist) is dangerous and can be misused is
not a valid reason to cosider it bad.
We already have a mechanism (public inheritance) that if misused is
more dangerous and we do not consider it bad; also when, missing a FIR
mechanism, i often see public inheritance wildly misused to emulate
it...

>Ploymorph PIMPL
[cut]
>However what should be done with the operators if there is more than one
>PIMPL inside?

If ambiguity arise consider them an compile-time errors and require
explicit disambiguation (explicit republication of the operator of the
desired PIML or explicit manual forwarding in a new operator who use
both).

>  Also assignment operator must not be automaticly
>generated...

This is good, it is already necessary to manually write it (if
wanted).
Sometimes i think automatically generated copy constructor and
assignement operator must be suppressed not only when a class contain
a reference but also when it contain a pointer.

>One might think that the constructors should be repeated as well by the
>compiler, but that seems to be a bit tricky: the can be more than one
>PIMPL... which causes combinatorical explosion of the possible
>contructors to be...  Also the constructor to be generated (even in the
>case of a single contained PIMPL) would not be a "simple delegation",
>since we need to use operator new in there.  And we may not want to use
>it, since we may use a factory to get our PIMPL.

This is definitably not the case i thinked of when suggesting
forwarding of constructors, in my use of polymorfic PIMPL's i have
never forwarded PIMPL constructors...

I was thinking more on the line of public derivation used to
add/change behaviour without adding data members, in this case it is
usual (for me, at least) to manually forward all constructors of the
base classe in a trivial way, and manual repetition of trivial tasks
is always tedious and error prone.

>About you proposal.  What is the real diferences (are *s) between these
>two?
>
>getHeight(...) = c_::getHeight(X x, Y x) const;
>
>Length Classname::getHeight( Pos x, Pos y) {
>  return c_->getHeight( x, y);
>}

Missing const and changed parameter types ?
(i suppose c_ is mutable otherwise the compiler will choke)
This do not make it a "real" republication, but instead a forwarding.
(maybe we must define in a more rigorous way these terms...)
sometimes this is useful/needed but i do think the other case (do not
change constness/parameter types) is more frequent when we need
republication...

>Obviously there isn't much more typing, so there is not much to save but
>there is a new syntax to learn: which is in general Very Bad.  We have
>already a lot to learn to grasp C++.  So adding soemthing new has to
>have extraordinary benefits to add it.

For a single function we have indeed a very little (and probably
unwhorty) gain with a specific republication syntax, but please
consider the case when we have some 20 different signature for a
member function C::DoSomething and we want to republish them all,
writing
 DoSomething(...) = c_::DoSomething;
we have not only far less typing, but above all we have a less error
prone republication because we can not make typing errors or miss some
function signature.

>But (if I understood your proposal properly) there is also a drawback of
>the new syntax: it has to get into the class definition, therefore
>effectively creating a stronger coupling than required by the problem:
>which is a Bad Thing.

I'm unsure what do you meant by "get into the class definition", can
you elaborate more ?
if you meant that the definition of reused classes must be visible,
well this is unavoidable also for all the others republications
proposals i have seen.

>So I believe that there is no way to gain here anything, doesn't matter
>how clever syntaces we come up with. :-(  We just need to tell what we
>mean.

I agree with the "We just need to tell what we mean" part, and for
this very reason i do think we need not only a FIR syntax but also a
PIR (Partial interface Republication) syntax so we can tell with more
precision to the compiler what we want.

Incidentally, i'm a bit confused, why do you have suggested the
 using public b_;
syntax if you think FIR is Very Bad ?
as a provocation ?

Regards,
Natale Fietta


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: Attila.Feher@lmf.ericsson.se (Attila Feher)
Date: Wed, 11 Sep 2002 18:30:34 +0000 (UTC)
Raw View
Natale Fietta wrote:
[SNIP]
> Obviously i like better the "using" solution for republication of ALL
> functions of a class (member or base), but when we need to republy
> only part of the interface the ability to change the name of a
> republied function can be useful.
> Also forwarding of constructors is interesting for me, probably it can
> be more useful in public derivation...
>
> What do you think ?

Looks interesing.  However I could not say just now what are the
implications.  I have found many times, that such designs, which require
these kind of missing language constracts are flawed in some way...
Please read me reply to Steve Heller, where I elaborate on why do I
think that dragging in a whole public interface in the Implemented-Using
case seems to be a fundamentally bad idea.

I have found two cases when some sort of "republication" could be good:

Ploymorph PIMPL

A special PIMPL where the PIMPL class inherits from an (asbtract?)
interface class.  In this case the PIMPL will be a pointer to the
interface class, and basically we want to populate the public interface
of the handle class using _all_ the public functions of the (abstract?)
base.  Meaning that not only "normal" virtual functions would be
propagated automaticly out to the public I/F of the but also the
operators - if they are virtual (which they should be in this case).
However what should be done with the operators if there is more than one
PIMPL inside?  Also assignment operator must not be automaticly
generated...

One might think that the constructors should be repeated as well by the
compiler, but that seems to be a bit tricky: the can be more than one
PIMPL... which causes combinatorical explosion of the possible
contructors to be...  Also the constructor to be generated (even in the
case of a single contained PIMPL) would not be a "simple delegation",
since we need to use operator new in there.  And we may not want to use
it, since we may use a factory to get our PIMPL.

Adding this all together means: we cannot or should not create the whole
interface automatically, meaning that the time or typing being saved is
not _all_ of it.  If we could save _all_ of it we could remove possible
human error.  But if we only remove part of the work the maintenance
burden is still there, but it is more easy to forget that one needs to
update two interfaces, since it gets more rare...  What I mean that I
believe it isn't worth the effort of a language feature, because finally
we may introduce more possible bugs.


Proto-types for "fast prototypes"

Don't we all hate typedefs?  We create nice ones to introduce fast
sometypes we wantto use, just to discover that since they are "only"
aliases, so we cannto overload functions or specialize templates by
using them.  We might be tempted to whish for a "real typedef" to say
that "for now this type is equvivalent to that one, but gimme a new type
please".  It can happen when one tries to do a proof of concept
prototype for some "higher level class" but wants to avoid to fully
define the classes used by it, like:

typedef std::string AddressLine;
typedef std::string NameLine;
typedef std::string City;
etc.

In this case it would be nice to be able to say:

class AddressLine : std::string;

to create a new type, identical to string.  However this is a plain
wrong route to take!  It is the same "I wanna have a cheap
implemented-in-terms-of" trap the original proposal has fallen into.  So
it has the all the drawbacks of that and in addition it has a sickening
effect on the prototyping effort as well!  People _are_ lazy - even if
this lazyness is "healthy" many times.  Since the above code is "so
simple" they will tend _not_ to change it to a full blown class - which
will end up in a non-encapsulated concept; a concept for which all the
operations are scattered throughout the code of other classes.  It is
clearly a Bad Idea.

So while it is tempting to try to save some typing it is not the kind of
lazyness which is healthy and without pretty bad consequences.

About you proposal.  What is the real diferences (are *s) between these
two?


getHeight(...) = c_::getHeight(X x, Y x) const;

Length Classname::getHeight( Pos x, Pos y) {
  return c_->getHeight( x, y);
}

Obviously there isn't much more typing, so there is not much to save but
there is a new syntax to learn: which is in general Very Bad.  We have
already a lot to learn to grasp C++.  So adding soemthing new has to
have extraordinary benefits to add it.

But (if I understood your proposal properly) there is also a drawback of
the new syntax: it has to get into the class definition, therefore
effectively creating a stronger coupling than required by the problem:
which is a Bad Thing.

To wrap it up: I believe (although I cannot just fully prove it yet)
that it is many times bad design leads to whish for those language
constructs which this thread discusses.  Also, while these constructs
may safe few bytes of typing, they certainly do not save us to from the
need of "telling what we mean".  Only we would tell it using (not much)
fewer keystrokes in your example.  Or much fewer keystrokes in my and
Mr. Heller's idea - but those also introduce the Very Bad Effect of
loosing control over the public interface of the class being declared
and letting the implementation type "show through".

So I believe that there is no way to gain here anything, doesn't matter
how clever syntaces we come up with. :-(  We just need to tell what we
mean.

Attila

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: Attila.Feher@lmf.ericsson.se (Attila Feher)
Date: Tue, 10 Sep 2002 15:43:01 +0000 (UTC)
Raw View
Steve Heller wrote:
[SNIP]
> Then I'm afraid I don't understand your proposal.

Sad.

> Could you give a
> more detailed explanation of exactly how you are proposing to modify
> the language,

Yes.

> what the rationale is,

That I have given already, I won't repeat myself.  The main reason for
proposing a slightly different solution is that your proposal would give
explicit language support for a design technique which is inferior due
to its strong coupling.  Read Herb and Scott on the topic.

> and how it works in a specific case?

Well, if you think about that elaborated example as yours... here it
comes:

Acutally I will try to be more elaborative as you were...

First: support for private inheritance.

This is _usually_ a bad design because:

- Y is not implemented using an X but _based_ on a X
- introduces unnecessary strong coupling
- exception safety of Y depends on the one of X
- protected functions of X become part of Y
- possible unwanted override of X virtual functions

_If_ one thinks the last two are OK, because one _needs_ those protected
functions or one _needs_ to override I have to disappoint the fellow: it
breaks the golden rule of one class _one_ responsibility.  So is Y
extending _or_ using X?

So, _if_ one has a very good reason to use it:

// The new style
class X {
public:
  int a();
  void b();
}

class Y: private X {
public:
  int a();
  using public X;
  char c();
};

This would have the effect of:

// The old style
class X {
public:
  int a();
  void b();
};

class Y: private X {
public:
  int a();
  using X::b;
  char c();
};

except that _if_ at any time one adds something to Xs' public interface
it would automagically appear in the public I/F of Y.  Which is the
reason I have _not_ proposed this solution before, because it _may_
cause surprises.  However I believe that my solution is more flexible
than your, so from the two "bad" (please do not take it personal) I
would prefer to have the one, which gives more advantages.

This using stuff introduces the problem of ODR violations, therefore the
using public line should always come _after_ the lines overriding the
original functions - meaning that if I write this:

// The new style
class X {
public:
  int a();
  void b();
}

class Y: private X {
public:
  using public X;
  int a();  // ERROR
  char c();
};

I will get an error: int a() is already declared in this scope.

>From this one can already deduce the mechanics of the new style using:
it introduces _all_, but the already declared names (as an alias) from
the named (by default public) section of the base class into the section
of the derived class where it appears.  Except those functions, which
are type specific (constructors, destructors, assignment, and all
operators).  Possible forms for the inheritance form:

using public <BaseClassName>;
using protected <BaseClassName>;
using private <BaseClassName>;

The third for only works for friends - obviously.  And it must not
appear anywhere else but in the private section of the derived class -
but I might not enforce this by a compiler diagnostics to leave freedom
for the programmer.

Second: support for value containment:

// The new style
class X {
public:
  int a();
  void b();
}

class Y {
  X x_;
public:
  int a();
  using public x_;
  char c();
};

This would have the effect of:

// The old style
class X {
public:
  int a();
  void b();
};

class Y {
  X x_;
public:
  int a();
  void b() { x_.b(); }
  char c();
};

Mechanics are exactly the same as for the one before, except that it
creates "automatic (inline) delegating functions".  Basically it means
that a call to y.b() will be replaced everywhere with a call to
y.x_.b(), much like as we use inline getters/setters to cross the
protection boundary of the class and still keep that very arms-distance
Herb refers to.

The value containment may _still_ be a too strong coupling, but at least
we got rid off the visibility problems of protected functions and
(unwanted) virtual function override.

Third: support for pointer (reference) containment:

// The new style
class X {
public:
  int a();
  void b();
}

class Y {
  X *x_;
public:
  Y() {...}
  ~Y() {...}
  Y( Y const &oth) {...}
  int a();
  using public x_;
  char c();
};

This would have the effect of:

// The old style
class X {
public:
  int a();
  void b();
};

class Y {
  X x_;
public:
  Y() {...}
  ~Y() {...}
  Y( Y const &oth) {...}
  int a();
  void b() { x_->b(); }
  char c();
};

Mechanics are still the same. Now it creates "automatic (inline)
delegating functions" using the pointer notation.  So a call to y.b()
will be replaced everywhere with a call to y.x_->b().  Reference
containment is basically the same syntax as the value containment, but I
list here because the coupling is different.

The pointer containment is the weakest possible coupling.


Some comments:

Of course, as long as we are inline and want automatic interface
generation based on the interface of the reused class, the coupling will
still be "stronger than we like", since the definition of the used class
must be known.  That is the reason why I suspect that this whole topic
(including your and my proposal) is mute: we type less but we inevitably
create strong coupling - at least for compile time, boosting the build
times to the skies.

If one uses a class based on a pure abstract class (interface) as the
implementation the decoupling can still be done:

struct I {
   virtual ...
   virtual ~I() = 0;
};

class Y {
   I *x_;
   Y();
...
   using public x_;
};

// in impl. file
#include "x.hpp"

Y::Y() {
   x_ = new X;
}


However I believe that this may be too much of a price to pay for not
typing some lines.  What do I mean?

Advantages of group using:

- less typing, automatic reuse of interface

Disadvantage:

- automatic reuse of interface

Hehe.  Why?  Because I have change class X! and I get class Y changed,
which (from the point of external observer) has _nothing_(!) to do with
class X!  So therefore I believe that while this techniques may save us
sometyping, they may introduce dangerous automatism into the code.  What
do I mean?  If the new operation added to X does something, which we
would need to _change_ (override) in Y (since it is _not_ an X)
_nothing_ will warn us!  Observe:

I use struct, because I hate to type public everywhere.  Use your
imagination. ;-)

struct Rect {
  Point ul_, lr_;
  setUL( Point const &ulc);
  setLR( Point const &lrc);
  void print() const;
  void overlaps( Rect const &oth) const;
// .. whatever
};

struct Square : private Rect {
  // Set the point, move the other to make square
  setUL( Point const &ulc);
  setLR( Point const &lrc);
  using public Rect;
};

All righty.  Then after 3.141592654 years comes programmer 007, who
created a service pack 1.34765E5 for the product containing Rect.  Our
company X downloads it, installs it.  A nice little new function has
been added to the Rect public interface: it resizes the Rectangle to
contain the given ellipse.  Programmer WC00 in our company reads the doc
of our Square class and reads: our interface is like the interface of
Rect, but our rect will always be a square.  So he starts to use the new
bound( Ellipse const &ell) function and...

Actually what we see above is the other issue not solved by either yours
or my proposal: we should have been able to _disable_ (make
non-existent) of the setLR function, because for the Square it would
make sense to set the upper right corner and the _size_, but not the
lower right corner...

So I believe that this proposals are questionable at best.  Yours is a
bit more than mine, since it wants explicit language support for a
questionable design.  But in both the programmer looses the control over
the interface of his own class!  The "implementation detail class X"
shows through!  Which is (IMHO) unacceptable if you want control over
your work.

What would be nice is to have something like this preferably in the
implementation file):

rettype Class::Function( parameters) = memberorsubclass::function;

That could be a form of short typeing delegation.  We still have the
control of our own interface, but we can at least save the retyping of
the arguments and the return keyword.  This could be used as:

int ManyTables::getNamedInt( std::string const & name) =
intTab_::getByName;

But this is something which came into my mind right now - one would need
to think a bit more to see the what effects it would have.

BBTW, _if_ my using example could be _only_ used with a special PIMPL
solution, where the "handle" around the PIMPL inherits from the same
interface class as the PIMPL itself: now _then_ and _only_ then I
believe that we could have a genuine "lifesaver"... well at least
repetitive motion disease saver (and still secure) by using a
one-line-delegation.

Attila

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: ros0230@iperbole.bologna.it (Natale Fietta)
Date: Wed, 11 Sep 2002 02:55:35 +0000 (UTC)
Raw View
On Fri, 6 Sep 2002 19:49:42 +0000 (UTC), Attila.Feher@lmf.ericsson.se
(Attila Feher) wrote:

>Steve Heller wrote:
>> My proposal is to add a new type of inheritance called "using". An
>[SNIP]

>Recently reading Herb Sutter about the Implemented-In-Terms-Of kind of
>connection between classes I believe that you have left out the
>"correct" implementation: having a member of that very type.  Thinking
>more about those lines I would rather be happy to be able to have a sort
>of "forward" keyword (whatever its final name would be), so that I could
>say:
[CUT]
>Now this of course could be done without any new keywords:
>
>class A {
> B b_;
> C c_;
>public:
> using public b_;
> using c_::getHeight( X x, Y x...);
>};
>
>I think that this is a bit more clear then introducing a new type of
>inheritance - and it is more flexible, since I could write this as well:
>
>class A : B, C {
>  public:
>  using public B;
>  using C::setWhatever( Whatever const &);
>};

Some weeks ago (in a private mail) i was hypotizing of a different
syntax for a similar function republication mechanism (it is an
evolution of a "using" syntax similar to your, modified because a
friend objected on the overload of meaning of the "using" keyword),
example follow:

class A: protected B
{
  C c_;
public:
  //this republy only the function with the specified signature
  getHeight(...) = c_::getHeight(X x, Y x) const;

  //we can also republy all visible functions with the specified name
  doWhatever(...) = c_::doWhatever;

  //for bases we can republy all public functions with the same name
  doSomething(...) = public B::doSomething;

  //and/or republy all protected functions with the same name
  doSomething(...) = protected B::doSomething;

  //in all case we can also republy using a different name for the
  //republicated function
  MakeThing(...) = protected B::doThing;

  //and finally i think can be useful to be able to "forward"
  //(not the same of republy) also public constructors
  A(...) = public B::B;
}

Obviously i like better the "using" solution for republication of ALL
functions of a class (member or base), but when we need to republy
only part of the interface the ability to change the name of a
republied function can be useful.
Also forwarding of constructors is interesting for me, probably it can
be more useful in public derivation...

What do you think ?

Regards,
Natale Fietta

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: steve@steveheller.com (Steve Heller)
Date: Mon, 9 Sep 2002 19:00:47 +0000 (UTC)
Raw View
steve@steveheller.com (Steve Heller) wrote:

>Justification:
>
>I have on several occasions had the following problem:
>
>A class X has *almost* the right semantics that I am looking for, but
>not quite. I want to use nearly everything in that class other than a
>few function overrides and a couple of new functions. However, X is
>not an ideal base class, perhaps because I don't have its source code
>and it doesn't have a virtual destructor, or just because it is a
>concrete class (which I would prefer not to inherit from).
>
>I am left with two possibilities for reusing the implementation of
>this class when creating my new class Y:
>
>1. Use public inheritance, override the functions that I want to
>change and add the new functions I want to add. This makes the new
>class easy to write and use, but it allows the logical error of
>assigning a Y object to an X*.
>
>2. Use private inheritance, adding "using" declarations for all of the
>functions in the original interface that I want to reuse and adding my
>own new code. This has the advantage of preventing misuse of an X* to
>point to a Y, but may require a significant number of extra
>declarations to allow use of the existing code base of X.

[3. I should have added that it would also be possible to declare a
member variable of type X in the declaration of type Y, but of course
that has much the same results as 2., and still does not solve the
problem that my proposal does.]

>My proposal is to add a new type of inheritance called "using". An
>example of its syntax would be as follows:
>
>-----------
>class X
>{
>int a();
>void b();
>}
>
>class Y: using X
>{
>int a();
>char c();
>};
>-----------
>
>This would have exactly the same effect as:
>
>-----------
>class X
>{
>public:
>int a();
>void b();
>};
>
>class Y: private X
>{
>using X::b;
>int a();
>char c();
>};
>
>-----------
>
>Obviously, this is not a major issue with such a small base class, but
>as the size of the base class increases, my proposal would reduce
>typing and the necessity for maintenance on Y when/if X changes.
>
>I would appreciate any comments on this proposal, especially from
>compiler writers who could tell me if it would complicate their lives
>significantly.
>
>Thanks.


--
Steve Heller
http://www.steveheller.com
Author of "C++: A Dialog", "Optimizing C++", and other books
Free online versions of "Who's Afraid of C++?" and "Optimizing C++" are now available
at http://www.steveheller.com/whos and http://www.steveheller.com/opt

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: steve@steveheller.com (Steve Heller)
Date: Mon, 9 Sep 2002 19:01:11 +0000 (UTC)
Raw View
wolof@freemail.hu (White Wolf) wrote:

>Steve Heller wrote:
>> [snip suggested other modification to C++]
>
>BTW, it wasn't a suggested "other modification", but a modification,
>which can support more cases, integrates more into the language and was
>meant to completely replace yours.
>
>WW a.k.a Attila

Then I'm afraid I don't understand your proposal. Could you give a
more detailed explanation of exactly how you are proposing to modify
the language, what the rationale is, and how it works in a specific
case?

--
Steve Heller
http://www.steveheller.com
Author of "C++: A Dialog", "Optimizing C++", and other books
Free online versions of "Who's Afraid of C++?" and "Optimizing C++" are now available
at http://www.steveheller.com/whos and http://www.steveheller.com/opt

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: steve@steveheller.com (Steve Heller)
Date: Fri, 6 Sep 2002 19:26:51 +0000 (UTC)
Raw View
Justification:

I have on several occasions had the following problem:

A class X has *almost* the right semantics that I am looking for, but
not quite. I want to use nearly everything in that class other than a
few function overrides and a couple of new functions. However, X is
not an ideal base class, perhaps because I don't have its source code
and it doesn't have a virtual destructor, or just because it is a
concrete class (which I would prefer not to inherit from).

I am left with two possibilities for reusing the implementation of
this class when creating my new class Y:

1. Use public inheritance, override the functions that I want to
change and add the new functions I want to add. This makes the new
class easy to write and use, but it allows the logical error of
assigning a Y object to an X*.

2. Use private inheritance, adding "using" declarations for all of the
functions in the original interface that I want to reuse and adding my
own new code. This has the advantage of preventing misuse of an X* to
point to a Y, but may require a significant number of extra
declarations to allow use of the existing code base of X.

My proposal is to add a new type of inheritance called "using". An
example of its syntax would be as follows:

-----------
class X
{
int a();
void b();
}

class Y: using X
{
int a();
char c();
};
-----------

This would have exactly the same effect as:

-----------
class X
{
public:
int a();
void b();
};

class Y: private X
{
using X::b;
int a();
char c();
};

-----------

Obviously, this is not a major issue with such a small base class, but
as the size of the base class increases, my proposal would reduce
typing and the necessity for maintenance on Y when/if X changes.

I would appreciate any comments on this proposal, especially from
compiler writers who could tell me if it would complicate their lives
significantly.

Thanks.

--
Steve Heller
http://www.steveheller.com
Author of "C++: A Dialog", "Optimizing C++", and other books
Free online versions of "Who's Afraid of C++?" and "Optimizing C++" are now available
at http://www.steveheller.com/whos and http://www.steveheller.com/opt

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: Attila.Feher@lmf.ericsson.se (Attila Feher)
Date: Fri, 6 Sep 2002 19:49:42 +0000 (UTC)
Raw View
Steve Heller wrote:
[SNIP]
> I am left with two possibilities for reusing the implementation of
> this class when creating my new class Y:
>
> 1. Use public inheritance, override the functions that I want to
> change and add the new functions I want to add. This makes the new
> class easy to write and use, but it allows the logical error of
> assigning a Y object to an X*.
>
> 2. Use private inheritance, adding "using" declarations for all of the
> functions in the original interface that I want to reuse and adding my
> own new code. This has the advantage of preventing misuse of an X* to
> point to a Y, but may require a significant number of extra
> declarations to allow use of the existing code base of X.
>
> My proposal is to add a new type of inheritance called "using". An
[SNIP]

Recently reading Herb Sutter about the Implemented-In-Terms-Of kind of
connection between classes I believe that you have left out the
"correct" implementation: having a member of that very type.  Thinking
more about those lines I would rather be happy to be able to have a sort
of "forward" keyword (whatever its final name would be), so that I could
say:

class A {
  B b_;
public:
  delegate_to_member b_ int f( int &);
};

Or even:

class A {
  B b_;
public:

  delegate_to_member public b_;

};

Now this of course could be done without any new keywords:

class A {
 B b_;
 C c_;
public:
 using public b_;
 using c_::getHeight( X x, Y x...);
};

Those above would be identical having an always-inline synonym in the
public (protected, private) interface to those functions.  It
could/should work for pointer members as well.

I think that this is a bit more clear then introducing a new type of
inheritance - and it is more flexible, since I could write this as well:

class A : B, C {
  public:
  using public B;
  using C::setWhatever( Whatever const &);
};

Attila

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: steve@steveheller.com (Steve Heller)
Date: Sat, 7 Sep 2002 16:35:20 +0000 (UTC)
Raw View
Attila.Feher@lmf.ericsson.se (Attila Feher) wrote:

>Steve Heller wrote:
>[SNIP]
>> I am left with two possibilities for reusing the implementation of
>> this class when creating my new class Y:
>>
>> 1. Use public inheritance, override the functions that I want to
>> change and add the new functions I want to add. This makes the new
>> class easy to write and use, but it allows the logical error of
>> assigning a Y object to an X*.
>>
>> 2. Use private inheritance, adding "using" declarations for all of the
>> functions in the original interface that I want to reuse and adding my
>> own new code. This has the advantage of preventing misuse of an X* to
>> point to a Y, but may require a significant number of extra
>> declarations to allow use of the existing code base of X.
>>
>> My proposal is to add a new type of inheritance called "using". An
>[SNIP]
>
>Recently reading Herb Sutter about the Implemented-In-Terms-Of kind of
>connection between classes I believe that you have left out the
>"correct" implementation: having a member of that very type.

If I understand your suggestion, that will not solve the problem
without changing the language in some way, because currently you have
to forward all the functions to the contained object explicitly rather
than implicitly.

[snip suggested other modification to C++]


--
Steve Heller
http://www.steveheller.com
Author of "C++: A Dialog", "Optimizing C++", and other books
Free online versions of "Who's Afraid of C++?" and "Optimizing C++" are now available
at http://www.steveheller.com/whos and http://www.steveheller.com/opt

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: gennaro_prota@yahoo.com (Gennaro Prota)
Date: Sat, 7 Sep 2002 22:45:01 +0000 (UTC)
Raw View
You already got an answer from Mr. Glassborow about your idea. Why are
you suggesting it again?

http://groups.google.com/groups?threadm=pb4b%24yEPnB58Ew1Q%40robinton.demon.co.uk


What about elaborating a complete proposal instead?


Genny.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: wolof@freemail.hu (White Wolf)
Date: Sat, 7 Sep 2002 22:45:27 +0000 (UTC)
Raw View
Steve Heller wrote:
[SNIP]
>>[SNIP]
>>
>>Recently reading Herb Sutter about the Implemented-In-Terms-Of kind of
>>connection between classes I believe that you have left out the
>>"correct" implementation: having a member of that very type.
>
> If I understand your suggestion, that will not solve the problem
> without changing the language in some way, because currently you have
> to forward all the functions to the contained object explicitly rather
> than implicitly.

No, and I haven't said that either.  What I have said is that by
changing a little bit the already existing features one will get a
solution which will not only solve your problem:

class B : private A {
   public:
    using public A;
};

but it also provides a way to support containement or the PIMPL idiom,
which is by far superior (PIMPL) to express implemented-in-terms-of
relationships than inheritance.  So you can as well take my words as
opposing to change the language to explicitly support a questionable
programming style.

WW a.k.a Attila

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: wolof@freemail.hu (White Wolf)
Date: Sat, 7 Sep 2002 22:45:36 +0000 (UTC)
Raw View
Steve Heller wrote:
> [snip suggested other modification to C++]

BTW, it wasn't a suggested "other modification", but a modification,
which can support more cases, integrates more into the language and was
meant to completely replace yours.

WW a.k.a Attila

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]