Thread: PIMPL in C... is it a bad idea?

  1. #1
    Registered User
    Join Date
    Mar 2019
    Posts
    5

    Question PIMPL in C... is it a bad idea?

    I have been forced into programming C++ for years and now I am coming back to C11 which is quite new to me after having only known C89 before coming to C++. Still... as a hardcore assembler programmer, it feels like coming home.

    One thing I liked a lot about C++ was the ability to create PIMPL idioms. There seems to be several ways to do it, but I used to write a purely abstract (definition-)class in the header file which contained only what the user would see and need, and in the CPP file there was an inheriting class which contained all the stuff that the user should never see, which I incorrectly call the 'hidden dirty code behind the definition' (because there should never be dirty code of course). A factory function created an instance of this class.

    I like to see this in C (without all the C++ disadvantages) and I am trying to do it as a test with implementing my own string handling API.

    So I created a typedef void* dstr and added a bunch of functions like:
    void dstr_free(dstr s);
    dstr dstr_new(size_t reserve);
    dstr dstr_from_cstr(const char *cstr);
    dstr dstr_asprintf(const char *fmt, ...);
    dstr dstr_vasprintf(const char *fmt, va_list varptr);
    void dstr_concat_cstr(dstr *s, const char *cs);
    void dstr_concat_dstr(dstr *s, const dstr cs);
    const char *dstr_cstr(const dstr s);
    ...

    The thing about this is that it enables me to implement dstr in any way I want without the user knowing how and without the user being able to fiddle with its internals (without hacking the memory of course). Later on, I can change the whole implementation and the user wouldn't need to know.

    The user doesn't know that the dstr typedef is being cast to a variable sized dstr_s struct (in the C file) which contains all the necessary optimization values and that this same pointer already contains the string itself (see EDIT below - I changed this because I understand that this isn't a good idea).

    But, would I change this system so that the string itself moves to a separate pointer, the user wouldn't notice and wouldn't have to change his code or even need to glance at the changes because the only thing he sees is that dstr is just a void*.

    The question is: is this a bad idea? I worry a bit about it actually being a void* (coming from C++, I don't really know how much type safety I need to let go of, coming from Assembler, this seems perfectly fine). Any other reasons why this would be a bad idea?

    And aside from that question: any comments/remarks on this? They are certainly welcome as I am trying to learn.

    EDIT:
    I just found out for myself that ingraining the string itself into a variable sized struct was not a good idea because its pointer may change, invalidating all references to it (dstrlist for example), so I'll be changing that. The question does remain valid though.
    Last edited by scippie; 03-03-2019 at 07:35 AM.

  2. #2
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,660
    There's no need to go all 'void*' in the public interface. If you want an example, just look at FILE*

    Code:
    // public.h
    struct dstr;
    void dstr_free(dstr *s);
    dstr *dstr_new(size_t reserve);
    dstr *dstr_from_cstr(const char *cstr);
    dstr *dstr_asprintf(const char *fmt, ...);
    dstr *dstr_vasprintf(const char *fmt, va_list varptr);
    void dstr_concat_cstr(dstr *s, const char *cs);
    void dstr_concat_dstr(dstr *s, const dstr cs);
    const char *dstr_cstr(const dstr *s);
    
    
    // private.h
    #include "public.h"
    struct dstr {
        // members
    };
    
    
    // private.c
    #include "public.h"
    #include "private.h"
    
    void dstr_free(dstr *s) {
        free(s->member); // where things were allocated
        free(s);
    }
    
    // and so on
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  3. #3
    Registered User
    Join Date
    Mar 2019
    Posts
    5
    Quote Originally Posted by Salem View Post
    Code:
    // private.h
    #include "public.h"
    struct dstr {
        // members
    };
    Is it necessary to have this separate "private" header file?
    Can't I just declare the struct in the c-file?

  4. #4
    Registered User
    Join Date
    Mar 2019
    Posts
    5
    Quote Originally Posted by Salem View Post
    Code:
    struct dstr;
    void dstr_free(struct dstr *s);
    ...
    With your version however, I need to add the 'struct' keyword everywhere (this wasn't of course the case with a void*), but it does give more type security.
    But it works (and without the extra private header file).

    EDIT: Never mind, should have listened to you in the first place and look up how struct FILE is implemented.

    struct dstr_s;
    typedef struct dstr_s dstr;
    Last edited by scippie; 03-03-2019 at 09:29 AM.

  5. #5
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by scippie
    I like to see this in C (without all the C++ disadvantages)
    C++ borrowed the pimpl idiom from C, where it might more commonly be known as the opaque pointer idiom, so there are no disadvantages to the idiom in C++ that C doesn't also have, other than disadvantages specific to specific implementations of the idiom that aren't feasible in C, like your use of inheritance in C++.

    EDIT: wait, I read your description again, and the way you use inheritance isn't a variation of the pimpl idiom. Rather, it is an instance of the abstract factory pattern.

    The key to the pimpl idiom involves storing or being a pointer to the implementation such that the implementation can be accessed internally from the interface or is the implementation of the interface such that it is opaque to the user. It does not typically involve returning a pointer to the implementation. You see the storage+forwarding in a common way of doing this in C++, whereas the typical C way uses an opaque pointer parameter for each interface function.

    Quote Originally Posted by scippie
    Is it necessary to have this separate "private" header file?
    No.

    Quote Originally Posted by scippie
    Can't I just declare the struct in the c-file?
    Yes, and I think this is better to ensure that the client doesn't accidentally depend on the implementation. On the other hand, it is possible that you might want to split the implementation into multiple files, in which case you would need a private header.
    Last edited by laserlight; 03-03-2019 at 01:30 PM.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  6. #6
    Registered User
    Join Date
    Mar 2019
    Posts
    5
    Quote Originally Posted by laserlight View Post
    EDIT: wait, I read your description again, and the way you use inheritance isn't a variation of the pimpl idiom. Rather, it is an instance of the abstract factory pattern.
    Hey yeah, you're right. Misinterpretation of my own problem, although it is solved now.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Best place to forward declare PIMPL class?
    By Ocifer in forum C++ Programming
    Replies: 19
    Last Post: 07-27-2015, 12:47 AM
  2. Compilation dependency and the pimpl idiom
    By ex-mortis in forum C++ Programming
    Replies: 18
    Last Post: 07-09-2012, 10:39 AM
  3. Understanding forward declarations of classes, pimpl
    By Boxknife in forum C++ Programming
    Replies: 2
    Last Post: 04-22-2010, 01:29 AM
  4. pimpl confuses me
    By manav in forum C++ Programming
    Replies: 8
    Last Post: 03-30-2008, 10:31 PM
  5. Inheritance in Pimpl idiom
    By George2 in forum C++ Programming
    Replies: 4
    Last Post: 03-19-2008, 09:32 PM

Tags for this Thread