Thread: Pimpl Idiom client/serve compile/link

  1. #1
    Registered User
    Join Date
    May 2006
    Posts
    1,579

    Pimpl Idiom client/serve compile/link

    Hello everyone,


    Suppose in Pimpl Idiom, we put private members into Pimpl class (implementation class).

    (http://www.gotw.ca/gotw/024.htm)

    My questions are, if we changed the Pimpl class and do not change visible parts of the whole component (class). There are two parties, component and client. Inside the component, there are two parts, Pimpl part and visible (to client) part.

    1. For the component, I think it needs re-compile, since private members of Pimpl part changed are referred by visible parts (public members refer to private members);

    2. I am not sure whether for the whole component, it needs to relink? I think it depends on whether other compile unit of the component invokes functions from the Pimpl part of component? Is it correct?

    3. I am not sure whether for the client, it needs re-link? If we provide the whole component as a static lib, client needs to re-link, right? And if we provide the whole component as a DLL, and client implicit links with it with import library, does the client needs relink again?


    thanks in advance,
    George

  2. #2
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    1) Component needs to be recompiled.
    2) Component needs to be relinked, of course. Otherwise you wouldn't get the new binary code into the thing. The implementations of the public part reside together with those of the private part. The point of PIMPL is that these implementations don't change and thus preserve binary compatibility.
    3) Client doesn't need to recompile. It does need to relink against the new binary. Of course, if the component is in a DLL, relinking happens at load time anyway, so there's nothing to do.
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  3. #3
    Registered User
    Join Date
    May 2006
    Posts
    1,579
    Thanks CornedBee,


    1.

    Quote Originally Posted by CornedBee View Post
    The point of PIMPL is that these implementations don't change and thus preserve binary compatibility.
    "These implementaitons" you mean public part?

    2.

    Quote Originally Posted by CornedBee View Post
    3) Client doesn't need to recompile. It does need to relink against the new binary.
    You mean if we ship the component in the form of static library?

    3.

    Quote Originally Posted by CornedBee View Post
    Of course, if the component is in a DLL, relinking happens at load time anyway, so there's nothing to do.
    You mean implicit linking or dynamic loading (LoadLibrary?) If you mean LoadLibrary, could it be called link? I think client does not link, just load dynamically the function pointers.


    regards,
    George

  4. #4
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    1) Yes.
    2) No, it always needs to relink. It's just that in case of DLLs, you don't notice.
    3) Both. And that's also called linking.
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  5. #5
    Registered User
    Join Date
    May 2006
    Posts
    1,579
    Thanks CornedBee,


    For (2) and (3), how do you think a linker is involved during dynamica loading of a DLL, e.g. LoadLibrary and GetProcAddress?

    Quote Originally Posted by CornedBee View Post
    2) No, it always needs to relink. It's just that in case of DLLs, you don't notice.
    3) Both. And that's also called linking.

    regards,
    George

  6. #6
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    The loader does the linking for DLLs.
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  7. #7
    Registered User
    Join Date
    May 2006
    Posts
    1,579
    I am confused, CornedBee. Do you mean when we call LoadLibrary, link.exe (MSVC linker program) will be invoked? In my previous understanding, if using LoadLibrary, only the address of exported function is retrieved by the loader when we call GetProcAddress.

    Any comments?

    Quote Originally Posted by CornedBee View Post
    The loader does the linking for DLLs.

    regards,
    George

  8. #8
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Link.exe is not part of the load process, it's part of the build process for the executable file [e.g. DLL and EXE].

    "The loader" is the part of the OS that loads an executable file, and it's dependant DLL portions into memory. This will include calling LoadLibrary [or it's internal counterpart(s) inside the kernel at least] to get the DLL loaded into the memory. This happens without the executable's code being run at all.

    And yes, that's ALSO called linking (perhaps the terms Static and Dynamic linking can be used to differentiate the two).

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  9. #9
    Registered User
    Join Date
    May 2006
    Posts
    1,579
    Thanks Mats,


    Sorry I want to confirm with you (since it is the 1st time to learn and derive the concept of linking), you mean when we load a DLL using LoadLibrary, it is called dynamic linking and even if no link.exe is invoked?

    Quote Originally Posted by matsp View Post
    Link.exe is not part of the load process, it's part of the build process for the executable file [e.g. DLL and EXE].

    "The loader" is the part of the OS that loads an executable file, and it's dependant DLL portions into memory. This will include calling LoadLibrary [or it's internal counterpart(s) inside the kernel at least] to get the DLL loaded into the memory. This happens without the executable's code being run at all.

    And yes, that's ALSO called linking (perhaps the terms Static and Dynamic linking can be used to differentiate the two).

    --
    Mats

    regards,
    George

  10. #10
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    The process of matching one binary executable file with another binary executable file is called linking. The difference between Static and and Dynamic linking[1] is:
    * Static linking is done immediately after producing the binary components, as part of the process to build the bindary executable file itself. This uses "link.exe" or something similar [e.g. gcc's "ld").

    * Dynamic linking is done at load-time, when an application is started in the system. This involves the same functions as LoadLibrary performs, but not necessarily using EXACTLY LoadLibrary, connecting the imported functions in one component with the exports of another component. [E.g. the C runtime library will connect to CreateFile somwhere in the code for "fopen()"].



    [1] Static and Dynamic linking is something I'm using here to clarify the situation, don't expect everyone around you to understand these names.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  11. #11
    Registered User
    Join Date
    May 2006
    Posts
    1,579
    Thanks Mats,


    Your description is clear. From my original question, Pimpl pattern only saves time for the client to compile, not saving the time for component to compile/link and also not saving the time for client to link. Right?

    From above point of view, Pimpl pattern does not save too much work of client and provide so magic and powerful functons. :-)

    Any comments?

    Quote Originally Posted by matsp View Post
    The process of matching one binary executable file with another binary executable file is called linking. The difference between Static and and Dynamic linking[1] is:
    * Static linking is done immediately after producing the binary components, as part of the process to build the bindary executable file itself. This uses "link.exe" or something similar [e.g. gcc's "ld").

    * Dynamic linking is done at load-time, when an application is started in the system. This involves the same functions as LoadLibrary performs, but not necessarily using EXACTLY LoadLibrary, connecting the imported functions in one component with the exports of another component. [E.g. the C runtime library will connect to CreateFile somwhere in the code for "fopen()"].



    [1] Static and Dynamic linking is something I'm using here to clarify the situation, don't expect everyone around you to understand these names.

    --
    Mats

    regards,
    George

  12. #12
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    The reason for using "pimpl" is more to do with "binary compatibility" than with actually reducing compile/link time. The point is that the interface to the public portion stays the same whatever the implementation "behind the scenes" is. This means that there is no changes to the code using the outer interface, and thus an executable that uses the outer interface (that is, the client) doesn't need to be recompiled. It still needs to link, either statically or dynamically to the new "behind the scense" code.

    Since the component "pimpl" is a pointer, it doesn't change size when the implementation changes. Consider for example that we have a container class specifically to store and retrieve C identifiers.

    Trivial implementation:
    Code:
    class identifier
    {
        public:
           void store(char *identifier, int id);
           char *retrieve(int id);
        private:
            char **list;  
            int size;
        ...
    }
    If we now have a brilliant idea of storing the data in a different way [e.g. a binary tree, hash-table or some other "better" data format], then we would have to recompile ANY code that uses this class.

    On the other hand, if we do this:
    Code:
    class identifier
    {
        public:
           void store(char *identifier, int id);
           char *retrieve(int id);
        private:
            _identifier *pimpl;
        ...
    }
    Now we can change the class "_identifier" as much as we like without affecting the code that only knows about identifier.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  13. #13
    Registered User
    Join Date
    May 2006
    Posts
    1,579
    Thanks Mats,


    Your reply is clear.

    Quote Originally Posted by matsp View Post
    The reason for using "pimpl" is more to do with "binary compatibility" than with actually reducing compile/link time. The point is that the interface to the public portion stays the same whatever the implementation "behind the scenes" is. This means that there is no changes to the code using the outer interface, and thus an executable that uses the outer interface (that is, the client) doesn't need to be recompiled. It still needs to link, either statically or dynamically to the new "behind the scense" code.

    Since the component "pimpl" is a pointer, it doesn't change size when the implementation changes. Consider for example that we have a container class specifically to store and retrieve C identifiers.

    Trivial implementation:
    Code:
    class identifier
    {
        public:
           void store(char *identifier, int id);
           char *retrieve(int id);
        private:
            char **list;  
            int size;
        ...
    }
    If we now have a brilliant idea of storing the data in a different way [e.g. a binary tree, hash-table or some other "better" data format], then we would have to recompile ANY code that uses this class.

    On the other hand, if we do this:
    Code:
    class identifier
    {
        public:
           void store(char *identifier, int id);
           char *retrieve(int id);
        private:
            _identifier *pimpl;
        ...
    }
    Now we can change the class "_identifier" as much as we like without affecting the code that only knows about identifier.

    --
    Mats

    regards,
    George

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Inheritance in Pimpl idiom
    By George2 in forum C++ Programming
    Replies: 4
    Last Post: 03-19-2008, 09:32 PM