December 31, 2005
On Sat, 31 Dec 2005 18:03:46 +1100, James Dunne <james.jdunne@gmail.com> wrote:

> For implementation hiding, just move the private members in classes to the end of the vtable, after all public and protected members (define this in the ABI and modify the reference compiler to guarantee this). Problem solved.
>
> No more private members need to be included in the generated header files because their vtable offsets are always greater than vtable offsets of public/protected members and will have no push/pull affect on them if left out.  Simply ignoring them in the _header_ class creates no binary compatibility issues.
>
> Const initializers; simply include them as well in the generated header classes for public/protected members to preserve correct offsets.
>
> Templates... well that's another story.

I'm sure this is all true, but wouldn't it be nice if we had some automated way of achieving this end, rather than relying on hand crafted code.

-- 
Derek Parnell
Melbourne, Australia
December 31, 2005
Derek Parnell wrote:
> On Sat, 31 Dec 2005 18:03:46 +1100, James Dunne <james.jdunne@gmail.com> wrote:
> 
>> For implementation hiding, just move the private members in classes to the end of the vtable, after all public and protected members (define this in the ABI and modify the reference compiler to guarantee this). Problem solved.
>>
>> No more private members need to be included in the generated header files because their vtable offsets are always greater than vtable offsets of public/protected members and will have no push/pull affect on them if left out.  Simply ignoring them in the _header_ class creates no binary compatibility issues.
>>
>> Const initializers; simply include them as well in the generated header classes for public/protected members to preserve correct offsets.
>>
>> Templates... well that's another story.
> 
> I'm sure this is all true, but wouldn't it be nice if we had some automated way of achieving this end, rather than relying on hand crafted code.
> 
> --Derek Parnell
> Melbourne, Australia

I think that was the idea he was trying to get across: it's not impossible to do.
December 31, 2005
"Kris" <fu@bar.com> wrote in message news:dp56kj$gc8$1@digitaldaemon.com...
> This setup does the right thing from an implementation-hiding aspect. It's what's been asked for many times in the past. Note that only public decalarations have been exposed. There's no class in there at all, just to make it as simple as possible. Unfortunately, I can't show the -H version. However, it's not much of a stretch to map the above onto Derek's original example, and assert that (for example) the implementation for both the factory method, and the static ctor() would be exposed (along with any other method considered to be inline-able) That would be no good, Walter. If it were the case, we'd have to ship all those proprietary imports too, along with everything they referenced ~ ad infinitum.
>
> I do wish I had a working compiler so this could be more concrete.

I know what you're talking about. But it just isn't practical. It isn't just turning off inlining - the types of the function parameters can reference private types or types in imported modules. So can parameter default values. So can const declarations. Templates too.

There are two solutions you can use. Both involve putting your interfaces in
a separate module. One means making a module just for your factory stub:
    ISearchEngine createSearchEngine (char[] someAttributes);
Another is to use the COM approach of having a magic cookie (GUIDs serve as
the magic cookie for COM) for each class, and pass that cookie to a generic
factory function that is itself an interface member.


December 31, 2005
"James Dunne" <james.jdunne@gmail.com> wrote in message news:dp5agf$ioj$1@digitaldaemon.com...
> For implementation hiding, just move the private members in classes to the end of the vtable, after all public and protected members (define this in the ABI and modify the reference compiler to guarantee this). Problem solved.

That works until you try to derive from it. <g>

> Const initializers; simply include them as well in the generated header classes for public/protected members to preserve correct offsets.

? Const initializers may refer to private declarations.

> Templates... well that's another story.

OOP is implementation hiding, templates are the antithesis of implementation hiding. In C++, exported templates were created to solve this problem, but it's pretty obvious to me that it does no such thing. I haven't been too popular in some circles for pointing this out <g>.


December 31, 2005
Walter Bright wrote:
> "Kris" <fu@bar.com> wrote in message news:dp56kj$gc8$1@digitaldaemon.com...
>> This setup does the right thing from an implementation-hiding aspect. It's what's been asked for many times in the past. Note that only public decalarations have been exposed. There's no class in there at all, just to make it as simple as possible. Unfortunately, I can't show the -H version. However, it's not much of a stretch to map the above onto Derek's original example, and assert that (for example) the implementation for both the factory method, and the static ctor() would be exposed (along with any other method considered to be inline-able) That would be no good, Walter. If it were the case, we'd have to ship all those proprietary imports too, along with everything they referenced ~ ad infinitum.
>>
>> I do wish I had a working compiler so this could be more concrete.
> 
> I know what you're talking about. But it just isn't practical. It isn't just turning off inlining - the types of the function parameters can reference private types or types in imported modules. So can parameter default values. So can const declarations. Templates too.

Ack!  I forgot about this.

By the way Kris, I found a good description of the pimpl idiom here:

http://www.gotw.ca/gotw/024.htm
http://www.gotw.ca/gotw/028.htm

> There are two solutions you can use. Both involve putting your interfaces in a separate module. One means making a module just for your factory stub:
>     ISearchEngine createSearchEngine (char[] someAttributes);
> Another is to use the COM approach of having a magic cookie (GUIDs serve as the magic cookie for COM) for each class, and pass that cookie to a generic factory function that is itself an interface member.

Aye.  See above :-)


Sean
December 31, 2005
Walter Bright wrote:
> "James Dunne" <james.jdunne@gmail.com> wrote in message 
> 
>> Templates... well that's another story.
> 
> OOP is implementation hiding, templates are the antithesis of implementation hiding. In C++, exported templates were created to solve this problem, but it's pretty obvious to me that it does no such thing. I haven't been too popular in some circles for pointing this out <g>. 

There's been a lot of confusion about the real purpose of "export" in C++, much like the -H option here ;-)  All the feature really provides is a way to speed compilation--implementation hiding is not really possible (as you've pointed out).  Whether potential benefit of "export" is worth the development cost is an issue of much contention.  The folks at EDG argued against the feature before it was made standard, but now they're arguing for it... possibly because they've spent so much time implementing it.  I don't think Microsoft has any plans of implementing "export," though I haven't heard anything from other vendors.


Sean
December 31, 2005
Walter Bright wrote:
> "James Dunne" <james.jdunne@gmail.com> wrote in message news:dp5agf$ioj$1@digitaldaemon.com...
> 
>>For implementation hiding, just move the private members in classes to the end of the vtable, after all public and protected members (define this in the ABI and modify the reference compiler to guarantee this). Problem solved.
> 
> That works until you try to derive from it. <g>
> 

*thinking...*

Ow.

Well, who says the binary layout of derived classes must be equivalent?  Isn't this just an implementation detail that most compilers assume is true in order to gain speed and ease of implementation for virtual/overridden methods?

I'll be thinking this one out for a while ...

>>Const initializers; simply include them as well in the generated header classes for public/protected members to preserve correct offsets.
> 
> 
> ? Const initializers may refer to private declarations.
> 

So there's the catcher... I didn't know that, thanks!

Well, why not const-fold out that private declaration into the initializer?

Oh right... again with the deriving... I always forget about the deriving...

> 
>>Templates... well that's another story.
> 
> 
> OOP is implementation hiding, templates are the antithesis of implementation hiding. In C++, exported templates were created to solve this problem, but it's pretty obvious to me that it does no such thing. I haven't been too popular in some circles for pointing this out <g>. 
> 

Anyone wishing to hide their implementation of templates should be reconsidering their worth to society. =)
December 31, 2005
Derek Parnell wrote:
> On Sat, 31 Dec 2005 18:03:46 +1100, James Dunne <james.jdunne@gmail.com>  wrote:
> 
>> For implementation hiding, just move the private members in classes to  the end of the vtable, after all public and protected members (define  this in the ABI and modify the reference compiler to guarantee this).  Problem solved.
>>
>> No more private members need to be included in the generated header  files because their vtable offsets are always greater than vtable  offsets of public/protected members and will have no push/pull affect on  them if left out.  Simply ignoring them in the _header_ class creates no  binary compatibility issues.
>>
>> Const initializers; simply include them as well in the generated header  classes for public/protected members to preserve correct offsets.
>>
>> Templates... well that's another story.
> 
> 
> I'm sure this is all true, but wouldn't it be nice if we had some  automated way of achieving this end, rather than relying on hand crafted  code.
> 

That's what I was saying... a compiler change.  It would be silly to require all D programmers to define their private members at the end of their classes.
December 31, 2005
Okay. I think there's an opportunity to clear this up via a few short questions. These refer back to the SearchEngine example posted previously (repeated below):

a) The example provided, where the SearchFactory.di file was hand-crafted? Will usage of that "di" module operate correctly?

b) You say below " it just isn't practical". Do you mean it is not technically feasible to mechanically extract the example SearchFactory.di from the given SearchFactory.d?


You'll hopefully note that example factory-module was explicitly written to avoid import references within all exposed types, has no templates, etc. Exactly the kind of thing a developer has to take responsibility over when decoupling usage from implementation (unless they explicitly wish to expose those also).

I have two more questions to follow up with, if you don't mind clearing this up?

- Kris


p.s. I'm reposting the example for the sake of clarity:

~~~~~~~~~~~~~~~~~~~
SearchInterfaces.d
~~~~~~~~~~~~~~~~~~~

module SearchInterfaces;

interface ISearchEngine
{
        ISearchItem[] lookup (char[] terms);
}

interface ISearchItem
{
        int relevancy();
        char[] retrievalUrl();
        char[] displaySnippet();
}


~~~~~~~~~~~~~~~~~~~
SearchFactory.d
~~~~~~~~~~~~~~~~~~~

module SearchFactory;


public import SearchInterfaces;

// private import a.bunch.of.proprietary.stuff;


// a factory for hooking up a client to the hidden implementation
public ISearchEngine createSearchEngine (char[] someAttributes)
{
        // potentially reference a.bunch.of.proprietary.stuff;
        return new XYX(someAttributes).
}


// do some proprietary setup
private static this()
{
        // potentially do a.bunch.of.proprietary.stuff;
}

~~~~~~~~~~~~~~~~~~~~~


That's the Factory implementation, which has a bunch of proprietary stuff in it along with references to proprietary imports. To correctly decouple a client from this implementation, one should provide another file (I'm covering Walter's statements here, from a long time ago) along the following lines:

~~~~~~~~~~~~~~~~~~~
SearchFactory.di
~~~~~~~~~~~~~~~~~~~

module SearchFactory;   // I believe this has to be the same name?

public import SearchInterfaces;

public ISearchEngine createSearchEngine (char[] someAttributes);

~~~~~~~~~~~~~~~~~~~




"Walter Bright" <newshound@digitalmars.com> wrote in message news:dp6hsf$1hdi$1@digitaldaemon.com...
>
> "Kris" <fu@bar.com> wrote in message news:dp56kj$gc8$1@digitaldaemon.com...
>> This setup does the right thing from an implementation-hiding aspect. It's what's been asked for many times in the past. Note that only public decalarations have been exposed. There's no class in there at all, just to make it as simple as possible. Unfortunately, I can't show the -H version. However, it's not much of a stretch to map the above onto Derek's original example, and assert that (for example) the implementation for both the factory method, and the static ctor() would be exposed (along with any other method considered to be inline-able) That would be no good, Walter. If it were the case, we'd have to ship all those proprietary imports too, along with everything they referenced ~ ad infinitum.
>>
>> I do wish I had a working compiler so this could be more concrete.
>
> I know what you're talking about. But it just isn't practical. It isn't just turning off inlining - the types of the function parameters can reference private types or types in imported modules. So can parameter default values. So can const declarations. Templates too.
>
> There are two solutions you can use. Both involve putting your interfaces
> in a separate module. One means making a module just for your factory
> stub:
>    ISearchEngine createSearchEngine (char[] someAttributes);
> Another is to use the COM approach of having a magic cookie (GUIDs serve
> as the magic cookie for COM) for each class, and pass that cookie to a
> generic factory function that is itself an interface member.
>
> 


December 31, 2005
"James Dunne" <james.jdunne@gmail.com> wrote in

> Anyone wishing to hide their implementation of templates should be reconsidering their worth to society. =)

Amen.