View mode: basic / threaded / horizontal-split · Log in · Help
July 16, 2005
Re: Private and Protected Inheritance.
Hi,

>Much, thanks for the explanation.

Sure thing.

>However, private and protected inheritance seem like very "niche" and 
>complex features for very little benefit.  In addition, it might not be 
>possible to implement well in D, as a private function cannot be virtual - 
>and changing a function's type from public to private when inherited 
>wouldn't fly, given D's inbuilt "virtual" determination... 

Can anyone who knows about the compiler enough confirm this?

--AJG.
July 16, 2005
Re: Private and Protected Inheritance.
Hi there,

>I don't know how hard would it be to implement, but I think there is a 
>better way around it:
>
>class A { /* stuff */ }
>
>class B { private A a; /* other stuff */ }
>
>I think that makes more sense, because if you want to hide A's interface 
>then B probably is not an A, it just uses it.
>
>Even the DeviceContext example, Graphics probably _uses_ a device 
>context to draw stuff, but it's not really a device context.
>Ofcourse I'm just making assumptions here, but my feeling is if you need 
>to hide the super classes interface then you probably are not of the 
>same type as the super class.

Yes, I mentioned that this is a possibility, but it's not ideal. It's lacking in
functionality because:

1) Graphics (B) would not be able to extend or override DeviceContext (A).
2) Graphics (B) has limited access to DeviceContext (A). All protected members
are gone.
3) If DeviceContext (B) was meant to be derived from, or is simply abstract,
then you need to create an intermediate class -hardly an elegant solution.

In essence, there is a marked difference between private containment (your
suggestion), which is also known as "HAS-ONE-OF," and private inheritance, aka
"IS-IMPLEMENTED-IN-TERMS-OF." It's incorrect to assume that just because a lower
class doesn't want to expose a super class' members it should not be one of the
same type. In this case, it's about the API and how you want your object
accessed. This is a great facility for that, and makes things simpler.

--AJG.
July 16, 2005
Re: Private and Protected Inheritance.
Hi Andrew,

Thanks for your suggestion. It's pretty amazing that the random example I picked
actually turns out to be implemented and it requires the _exact_ thing I was
talking about. I feel validated for some reason.

Indeed the package attribute is of _some_ help and could be hacked in to achieve
similar functionality (to what we need, true private inheritance). There are
various problems though:

1) Package access is semantically confusing at the moment. Nobody's really sure
what it's supposed to do. It's incomplete and unreliable. Or at least:
2) Package access is buggy.
3) Package access is still "friend" access. If you have your classes in the same
file you lose the effect.
4) You need to modify the super class to hack the thing in. What if you can't
edit that class? Why should you have to modify a super class for the behaviour
of some unknown lower class? What if you don't have proper access to the code?
Or, if an ABI eventually matures, what if the source is not even there? For that
you need private inheritance. It's elegant and simple.

As a side note, I checked out the harmonia page and it looks really awesome. If
I understand correctly, there are no OS-widgets at all? That's pretty
impressive.

--AJG.


>Try this:
>
>From Harmonia:
>---------------------------------------------------
>module harmonia.ui.native.win32graphics;
>
>class NativeGraphics
>{
>   package
>   {
>      // ... various native objects ...
>      void nativeDrawRect(rect rc) { .... }
>   }
>}
>---------------------------------------------------
>module harmonia.gx.graphics;
>
>class Graphics: NativeGraphics
>{
>    void drawRect(rect rc)
>    {
>      nativeDrawRect(rc);
>    }
>}
>
>--------------------------
>
>void testDraw(Graphics g)
>  {
>    g.nativeDrawRect(place);
>//  Error: class harmonia.gx.graphics.Graphics
>//  member nativeDrawRect is not accessible
>  }
>
>---------------------------
July 16, 2005
Re: Private and Protected Inheritance.
Hi there,

>But... but... isn't this exactly what interfaces are for? Define an IGraphics
>interface with DrawCircle(), DrawSquare() etc, have your Graphics class
>implement that interface, and give an IGraphics to client code instead of a
>Graphics.

This is yet another incomplete way to solve the problem.

1) This introduces redundancy (rarely good in code), in vain. You must define
the interface and then implement it, maintaining the same thing twice, despite
the fact that there will likely only ever be one implementation. I understand
the use of interfaces for situations where at least they'll be useful multiple
times, but this is hardly the case.

2) Graphics (and thus, DeviceContext) are now essentially sealed. Neither can be
extended. I guess you could inherit from IGraphics and then use that, but see
point 1. Even then, the actual implementations would be locked and unavailable
for reuse.

3) Also, what do you mean give an IGraphics? You can't just give an IGraphics,
it would be useless to users. At some point, they're going to need to initialize
a _real_ Graphics and use that. Then you get the whole problem back again, since
DeviceContext is exposed anew.

The pattern I see is that the interface approach is usually useful only when the
implementation is not relevant and not required. In this case, the
implementation is important, so it doesn't work well. I want to use and keep the
implementation available through the object hierarchy, but with the _right_
access modifier (hence, the need for private).

>I meant "what it means semantically", rather than what the syntax looks like.
>Public inheritance means "Derived is substitutable for Base". Private
>inheritance means "Derived reuses code from base without exposing that fact in
>its interface". What does protected inheritance mean?

I'll take a shot: "Derived reuses code from base without exposing that fact in
its interface, while keeping the interface open for subclassing."

Cheers,
--AJG.
July 16, 2005
Re: Private and Protected Inheritance.
In article <dba19s$mqs$1@digitaldaemon.com>, AJG says...
>
>>But... but... isn't this exactly what interfaces are for?
>
>1) This introduces redundancy (rarely good in code), in vain. You must define
>the interface and then implement it, maintaining the same thing twice, despite
>the fact that there will likely only ever be one implementation.

It's not a major burden in practice. The big risk with redundancy is things
getting out of sync, and the compiler will let you know if this happens with
interfaces and their implementations.

Maybe we're coming from different places; I'm mostly doing agile C# development
these days, and interfaces almost always have at least one "other"
implementation, even if it's only a mock or stub for unit-testing client code.

>2) Graphics (and thus, DeviceContext) are now essentially sealed. Neither can 
>be extended. 

Why not?

# interface IGraphics { void DrawSquare(); }
# class Graphics : IGraphics { void DrawSquare() {} }
#
# // Dammit, now I need to draw teapots too. OK...
#
# interface IMyGraphics : IGraphics { void DrawTeapot(); }
# class MyGraphics : Graphics, IMyGraphics { void DrawTeapot() {} }

>3) Also, what do you mean give an IGraphics? You can't just give an IGraphics,
>it would be useless to users. 

I mean that while you're probably givin them a Graphics *object*, the argument
and/or retval types they see will be IGraphics. They don't know that it's a
Graphics, so they can't see any of the implementation bits they shouldn't.

>I'll take a shot: "Derived reuses code from base without exposing that fact in
>its interface, while keeping the interface open for subclassing."

In practice, I've found that (for C#/Java) interfaces work fine. For C++ you'd
normally either use composition or turn things around and have
DeviceContextGraphics (implementation) derive from Graphics (interface), using
something like the GoF Template Method pattern and/or the "Non Virtual
Interface" idiom (see e.g. http://www.gotw.ca/publications/mill18.htm)

cheers
Mike
Next ›   Last »
1 2
Top | Discussion index | About this forum | D home