Public/private in C

Discussion in 'C Programming' started by jacob navia, Mar 21, 2010.

  1. jacob navia

    jacob navia Guest

    As you may have noticed, when I proposed the iterator object I splitted
    the object into a public part (the first 3 fields) an an undisclosed
    part specific to each iterator.

    This inheritance implementation looks like this:

    In the header file:

    typedef struct PublicStruct {
    // public fields
    } Public;

    In the implementation file (.c) we do:

    typedef struct Inherited {
    Public p;
    // follow the private fields
    } Private;

    The interface for all functions is just the public structure:

    void fn1(Public *);
    void fn2(Public *);

    The implementation of fn1 however, does this:

    void fn1(Public *p) {
    Private *pri = (Private *)p;

    // Work with the private struct.
    // It is assumed that the pointer
    // handed down is actually a private
    // pointer

    }

    Obviously this doesn't have any compiler support
    but works quite well in practice. You can add a
    "magic" number somewhere in the private struct
    in the debug version to catch mistakes when passing
    the structures.

    Obviously you aren't supposed to copy the public object since you do not
    know what is behind. A way to avoid that would be to add a VLA:

    typedef struct PublicStruct {
    // public fields
    // ...
    // private fields follow:
    char private[];
    } Public;


    YES I KNOW.

    C++/Java/C# do this MUCH better, but they have other drawbacks
    that make a pure C solution MUCH better. Thank you.
     
    jacob navia, Mar 21, 2010
    #1
    1. Advertising

  2. jacob navia

    Ian Collins Guest

    On 03/22/10 11:20 AM, jacob navia wrote:
    > As you may have noticed, when I proposed the iterator object I splitted
    > the object into a public part (the first 3 fields) an an undisclosed
    > part specific to each iterator.


    <snip example>

    > Obviously this doesn't have any compiler support
    > but works quite well in practice. You can add a
    > "magic" number somewhere in the private struct
    > in the debug version to catch mistakes when passing
    > the structures.
    >
    > Obviously you aren't supposed to copy the public object since you do not
    > know what is behind. A way to avoid that would be to add a VLA:
    >
    > typedef struct PublicStruct {
    > // public fields
    > // ...
    > // private fields follow:
    > char private[];


    This isn't a VLA, its an example of the "struct hack".

    > } Public;


    You can still copy these. It's not a good idea, but there's nothing to
    prevent the copy.

    > YES I KNOW.
    >
    > C++/Java/C# do this MUCH better, but they have other drawbacks
    > that make a pure C solution MUCH better. Thank you.


    In this instance, please elaborate!

    --
    Ian Collins
     
    Ian Collins, Mar 21, 2010
    #2
    1. Advertising

  3. Ian Collins <> writes:
    > On 03/22/10 11:20 AM, jacob navia wrote:

    [...]
    >> typedef struct PublicStruct {
    >> // public fields
    >> // ...
    >> // private fields follow:
    >> char private[];

    >
    > This isn't a VLA, its an example of the "struct hack".
    >
    >> } Public;

    [...]

    More precisely, it's a "flexible array member", C99's replacement for
    the "struct hack".

    Incidentally, jacob's declaration for the struct was properly
    indented, but the indentation vanished in Ian's followup, probably
    because of the use of tabs. At least for Usenet posts, spaces are
    better than tabs for indentation, since news software doesn't always
    deal sanely with tabs.

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    Nokia
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
     
    Keith Thompson, Mar 21, 2010
    #3
  4. jacob navia

    Hamiral Guest

    jacob navia wrote:
    > As you may have noticed, when I proposed the iterator object I splitted
    > the object into a public part (the first 3 fields) an an undisclosed
    > part specific to each iterator.


    Interesting.
    Do you have something similar for inheritance, or... polymorphism ? That
    would be great :)

    Ham
     
    Hamiral, Mar 21, 2010
    #4
  5. jacob navia

    ImpalerCore Guest

    On Mar 21, 6:20 pm, jacob navia <> wrote:
    > As you may have noticed, when I proposed the iterator object I splitted
    > the object into a public part (the first 3 fields) an an undisclosed
    > part specific to each iterator.
    >
    > This inheritance implementation looks like this:
    >
    > In the header file:
    >
    > typedef struct PublicStruct {
    >         // public fields
    >
    > } Public;
    >
    > In the implementation file (.c) we do:
    >
    > typedef struct Inherited {
    >         Public p;
    >         // follow the private fields
    >
    > } Private;
    >
    > The interface for all functions is just the public structure:
    >
    > void fn1(Public *);
    > void fn2(Public *);
    >
    > The implementation of fn1 however, does this:
    >
    > void fn1(Public *p) {
    >         Private *pri = (Private *)p;
    >
    >         // Work with the private struct.
    >         // It is assumed that the pointer
    >         // handed down is actually a private
    >         // pointer
    >
    > }
    >
    > Obviously this doesn't have any compiler support
    > but works quite well in practice. You can add a
    > "magic" number somewhere in the private struct
    > in the debug version to catch mistakes when passing
    > the structures.
    >
    > Obviously you aren't supposed to copy the public object since you do not
    > know what is behind. A way to avoid that would be to add a VLA:
    >
    > typedef struct PublicStruct {
    >         // public fields
    >         // ...
    >         // private fields follow:
    >         char private[];
    >
    > } Public;
    >
    > YES I KNOW.
    >
    > C++/Java/C# do this MUCH better, but they have other drawbacks
    > that make a pure C solution MUCH better. Thank you.


    Personally I think implementing some public/private separation is
    outside the scope of C. Grafting this OO paradigm into C is purely
    arbitrary at best, confusing and complex at worst. C wants people to
    get their hands dirty, and doesn't do a whole lot to protect them.

    Again, you say a pure C solution is MUCH better, but I haven't seen a
    really cool use-case that says "Yeah, I want to try it out!". If I
    wanted to make something private in C, I'd just give the "private"
    members a hideously long name so that most people will just be annoyed/
    bored to type it out and use the "public" parts ;)

    Best regards,
    John D.
     
    ImpalerCore, Mar 22, 2010
    #5
  6. jacob navia

    jacob navia Guest

    ImpalerCore a écrit :

    > Personally I think implementing some public/private separation is
    > outside the scope of C. Grafting this OO paradigm into C is purely
    > arbitrary at best, confusing and complex at worst. C wants people to
    > get their hands dirty, and doesn't do a whole lot to protect them.
    >


    Well, as you may have noticed, I proposed a common iterator object for
    iterating through ANY container in my library. Obviously that object
    can't be a SINGLE type, it must be several since it must have the specific
    knowledge of each container, AND it must offer a COMMON interface, so user
    code is independent of the container.

    It is not just "a matter of protecting people from themselves", it is
    just that is impossible to make a COMMON type for all container iterators
    if each iterator exposes its interface.

    The solution is then, to define a common interface with a few
    function pointers that is shared by all containers. User code uses that
    interface

    typedef struct _iterator {
    void (*Getnext)(structb_iterator *);
    // Some other public function pointers
    char private[]; // Document that this is a variable length structure
    } Iterator;

    In the file of the container implementation (say list.c) I
    define

    typedef struct tagListIterator {
    Iterator it;
    // Private fields follow
    List *list;
    unsigned timestamp;
    // etc
    } ListIterator;

    Now, I can define

    static void *GetNext(Iterator *it)
    {
    ListIterator *li = (ListIterator *)it;

    // And now I can use the private fields
    // in this implementation.
    }

    The advantage of this is that I can EXTEND a public structure with private
    parts, something similar to simple inheritance in C.

    > Again, you say a pure C solution is MUCH better, but I haven't seen a
    > really cool use-case that says "Yeah, I want to try it out!".


    When you write a library, it is very handy since it allows to present a common
    interface for a set of different objects

    > If I
    > wanted to make something private in C, I'd just give the "private"
    > members a hideously long name so that most people will just be annoyed/
    > bored to type it out and use the "public" parts ;)
    >
    > Best regards,
    > John D.


    It is not so much a "private" vs public stuff but it is a thing of
    interfacing different objects of different types through a common interface.
     
    jacob navia, Mar 22, 2010
    #6
  7. jacob navia

    ImpalerCore Guest

    On Mar 22, 2:57 pm, jacob navia <> wrote:
    > ImpalerCore a écrit :
    >
    > > Personally I think implementing some public/private separation is
    > > outside the scope of C.  Grafting this OO paradigm into C is purely
    > > arbitrary at best, confusing and complex at worst.  C wants people to
    > > get their hands dirty, and doesn't do a whole lot to protect them.

    >
    > Well, as you may have noticed, I proposed a common iterator object for
    > iterating through ANY container in my library. Obviously that object
    > can't be a SINGLE type, it must be several since it must have the specific
    > knowledge of each container, AND it must offer a COMMON interface, so user
    > code is independent of the container.
    >
    > It is not just "a matter of protecting people from themselves", it is
    > just that is impossible to make a COMMON type for all container iterators
    > if each iterator exposes its interface.
    >
    > The solution is then, to define a common interface with a few
    > function pointers that is shared by all containers. User code uses that
    > interface
    >
    > typedef struct _iterator {
    >         void (*Getnext)(structb_iterator *);
    >         // Some other public function pointers
    >         char private[]; // Document that this is a variable length structure
    >
    > } Iterator;
    >
    > In the file of the container implementation (say list.c) I
    > define
    >
    > typedef struct tagListIterator {
    >         Iterator it;
    >         // Private fields follow
    >         List *list;
    >         unsigned timestamp;
    >         // etc
    >
    > } ListIterator;
    >
    > Now, I can define
    >
    > static void *GetNext(Iterator *it)
    > {
    >         ListIterator *li = (ListIterator *)it;
    >
    >         // And now I can use the private fields
    >         // in this implementation.
    >
    > }
    >
    > The advantage of this is that I can EXTEND a public structure with private
    > parts, something similar to simple inheritance in C.


    I can see your viewpoint better now, between this and your other
    responses.

    > > Again, you say a pure C solution is MUCH better, but I haven't seen a
    > > really cool use-case that says "Yeah, I want to try it out!".

    >
    > When you write a library, it is very handy since it allows to present a common
    > interface for a set of different objects


    Fair enough, I'll wait to see how it all works when you release
    something.

    > > If I
    > > wanted to make something private in C, I'd just give the "private"
    > > members a hideously long name so that most people will just be annoyed/
    > > bored to type it out and use the "public" parts ;)

    >
    > > Best regards,
    > > John D.

    >
    > It is not so much a "private" vs public stuff but it is a thing of
    > interfacing different objects of different types through a common interface.


    I suppose I took the private/public too literally. Probably a by-
    product of learning C++ then coming to C I suppose.

    Best regards,
    John D.
     
    ImpalerCore, Mar 23, 2010
    #7
  8. On Mar 21, 5:20 pm, jacob navia <> wrote:
    > As you may have noticed, when I proposed the iterator object I splitted
    > the object into a public part (the first 3 fields) an an undisclosed
    > part specific to each iterator.
    >
    > This inheritance implementation looks like this:
    >
    > In the header file:
    >
    > typedef struct PublicStruct {
    >         // public fields
    >
    > } Public;
    >
    > In the implementation file (.c) we do:
    >
    > typedef struct Inherited {
    >         Public p;
    >         // follow the private fields
    >
    > } Private;
    >
    > The interface for all functions is just the public structure:
    >
    > void fn1(Public *);
    > void fn2(Public *);
    >
    > The implementation of fn1 however, does this:
    >
    > void fn1(Public *p) {
    >         Private *pri = (Private *)p;
    >
    >         // Work with the private struct.
    >         // It is assumed that the pointer
    >         // handed down is actually a private
    >         // pointer
    >
    > }
    >
    > Obviously this doesn't have any compiler support
    > but works quite well in practice. You can add a
    > "magic" number somewhere in the private struct
    > in the debug version to catch mistakes when passing
    > the structures.
    >
    > Obviously you aren't supposed to copy the public object since you do not
    > know what is behind. A way to avoid that would be to add a VLA:
    >
    > typedef struct PublicStruct {
    >         // public fields
    >         // ...
    >         // private fields follow:
    >         char private[];
    >
    > } Public;
    >
    > YES I KNOW.
    >
    > C++/Java/C# do this MUCH better, but they have other drawbacks
    > that make a pure C solution MUCH better. Thank you.



    Am not sure if there is a question here. Also, you may already know
    this, but you can control/restrict access by using the 'pimpl' idiom
    (also known as the 'opaque structure'). Herb Sutter has written an
    article or two regarding this (yes, they are C++ based, but the ideas
    can be applied to C).

    Basically you forward declare a structure that you want to be private
    like so:

    struct MyStructPrivates; /* forward declaration */

    struct MyStruct
    {
    /* All your "public" stuff here */

    struct MyStructPrivates *PtrToPrivate;
    };

    In the declaration of MyStructPrivates, you include the declaration of
    MyStruct so you have access to the public parts of your struct.

    The declaration of MyStructPrivates does not even have to be delivered
    to the library user. Further, if anything changes in the
    implementation of MyStructPrivates, your library users will remain
    unaffected.

    I haven't followed the other thread or read your iterator design, it
    is possible I am way off-tangent here.

    - Anand
     
    Anand Hariharan, Mar 23, 2010
    #8
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Charles A. Lackman
    Replies:
    1
    Views:
    1,370
    smith
    Dec 8, 2004
  2. SpamProof
    Replies:
    0
    Views:
    581
    SpamProof
    Oct 21, 2003
  3. Kevin Spencer
    Replies:
    2
    Views:
    3,312
    Kevin Spencer
    Sep 15, 2004
  4. qazmlp
    Replies:
    19
    Views:
    797
    Daniel T.
    Feb 4, 2004
  5. DaveLessnau
    Replies:
    3
    Views:
    428
    Howard
    May 16, 2005
Loading...

Share This Page