Why localize structures in this case. - Unix

This is a discussion on Why localize structures in this case. - Unix ; Littered through the 10,000 + lines of some Berekely Database code, I keep seeing the following DBHANDLE db_open(const char *pathname, int oflag,,,) { DB *db; /*code*/ return(db); } static DB * _db_allocate(int namelen) { DB *db; /*code*/ return(db); } char ...

+ Reply to Thread
Results 1 to 20 of 20

Thread: Why localize structures in this case.

  1. Why localize structures in this case.

    Littered through the 10,000 + lines of some Berekely Database code, I
    keep seeing the following

    DBHANDLE
    db_open(const char *pathname, int oflag,,,)
    {
    DB *db;
    /*code*/
    return(db);
    }

    static DB *
    _db_allocate(int namelen)
    {
    DB *db;
    /*code*/
    return(db);
    }

    char *
    db_fetch(DBHANDLE h, const char *key)
    {
    DB *db=h;
    /*code*/
    return(ptr);
    }


    The question is, why have

    DB *db

    inside the function versus being passed as the formal parameters. Ie,
    why not have something like

    static DB *
    _db_allocate(int namelen, DB *db)

    Actually, I've seen this kind of coding move in a lot of C and Unix
    code. I just chose the Berkeley Database Code because I can make some
    heads or tails out of it.


    Chad


  2. Re: Why localize structures in this case.

    On Oct 30, 6:21 pm, Chad wrote:
    > Littered through the 10,000 + lines of some Berekely Database code, I
    > keep seeing the following
    >
    > DBHANDLE
    > db_open(const char *pathname, int oflag,,,)
    > {
    > DB *db;
    > /*code*/
    > return(db);
    >
    > }
    >
    > static DB *
    > _db_allocate(int namelen)
    > {
    > DB *db;
    > /*code*/
    > return(db);
    >
    > }
    >
    > char *
    > db_fetch(DBHANDLE h, const char *key)
    > {
    > DB *db=h;
    > /*code*/
    > return(ptr);
    >
    > }
    >
    > The question is, why have
    >
    > DB *db
    >
    > inside the function versus being passed as the formal parameters. Ie,
    > why not have something like
    >
    > static DB *
    > _db_allocate(int namelen, DB *db)
    >
    > Actually, I've seen this kind of coding move in a lot of C and Unix
    > code. I just chose the Berkeley Database Code because I can make some
    > heads or tails out of it.


    The idea is to create an abstraction called DBHANDLE used to access a
    table.
    The reason for doing this is that you do not want the end-users poking
    around inside the guts of the DB*.
    All they get is some opaque little thingy to reference the table
    with. If they start poking around in the innards of the DB*, chances
    are good they will break something.

    It is no different than fopen(), fread(), fwrite() passing around a
    FILE *.
    It's just another way of saying:
    "This thing is mine, and as the inventor I know how to use it. If you
    start fiddling with it, we're all going to get into trouble. So don't
    touch it."


  3. Re: Why localize structures in this case.

    On Oct 30, 6:36 pm, user923005 wrote:
    > On Oct 30, 6:21 pm, Chad wrote:
    >
    >
    >
    > > Littered through the 10,000 + lines of some Berekely Database code, I
    > > keep seeing the following

    >
    > > DBHANDLE
    > > db_open(const char *pathname, int oflag,,,)
    > > {
    > > DB *db;
    > > /*code*/
    > > return(db);

    >
    > > }

    >
    > > static DB *
    > > _db_allocate(int namelen)
    > > {
    > > DB *db;
    > > /*code*/
    > > return(db);

    >
    > > }

    >
    > > char *
    > > db_fetch(DBHANDLE h, const char *key)
    > > {
    > > DB *db=h;
    > > /*code*/
    > > return(ptr);

    >
    > > }

    >
    > > The question is, why have

    >
    > > DB *db

    >
    > > inside the function versus being passed as the formal parameters. Ie,
    > > why not have something like

    >
    > > static DB *
    > > _db_allocate(int namelen, DB *db)

    >
    > > Actually, I've seen this kind of coding move in a lot of C and Unix
    > > code. I just chose the Berkeley Database Code because I can make some
    > > heads or tails out of it.

    >
    > The idea is to create an abstraction called DBHANDLE used to access a
    > table.
    > The reason for doing this is that you do not want the end-users poking
    > around inside the guts of the DB*.
    > All they get is some opaque little thingy to reference the table
    > with. If they start poking around in the innards of the DB*, chances
    > are good they will break something.
    >
    > It is no different than fopen(), fread(), fwrite() passing around a
    > FILE *.
    > It's just another way of saying:
    > "This thing is mine, and as the inventor I know how to use it. If you
    > start fiddling with it, we're all going to get into trouble. So don't
    > touch it."



    Maybe I'm missing the broader picture, but couldn't a user still
    fiddle with the guts of DB? I mean, couldnt a user do something like

    /*untested code*/
    #include

    int main(void)
    {
    DBHANDLE *db;
    db->data="I think I just broke another part of the program";

    return 0;
    }




  4. Re: Why localize structures in this case.

    On Oct 30, 6:36 pm, user923005 wrote:
    > On Oct 30, 6:21 pm, Chad wrote:
    >
    >
    >
    > > Littered through the 10,000 + lines of some Berekely Database code, I
    > > keep seeing the following

    >
    > > DBHANDLE
    > > db_open(const char *pathname, int oflag,,,)
    > > {
    > > DB *db;
    > > /*code*/
    > > return(db);

    >
    > > }

    >
    > > static DB *
    > > _db_allocate(int namelen)
    > > {
    > > DB *db;
    > > /*code*/
    > > return(db);

    >
    > > }

    >
    > > char *
    > > db_fetch(DBHANDLE h, const char *key)
    > > {
    > > DB *db=h;
    > > /*code*/
    > > return(ptr);

    >
    > > }

    >
    > > The question is, why have

    >
    > > DB *db

    >
    > > inside the function versus being passed as the formal parameters. Ie,
    > > why not have something like

    >
    > > static DB *
    > > _db_allocate(int namelen, DB *db)

    >
    > > Actually, I've seen this kind of coding move in a lot of C and Unix
    > > code. I just chose the Berkeley Database Code because I can make some
    > > heads or tails out of it.

    >
    > The idea is to create an abstraction called DBHANDLE used to access a
    > table.
    > The reason for doing this is that you do not want the end-users poking
    > around inside the guts of the DB*.
    > All they get is some opaque little thingy to reference the table
    > with. If they start poking around in the innards of the DB*, chances
    > are good they will break something.
    >
    > It is no different than fopen(), fread(), fwrite() passing around a
    > FILE *.
    > It's just another way of saying:
    > "This thing is mine, and as the inventor I know how to use it. If you
    > start fiddling with it, we're all going to get into trouble. So don't
    > touch it."



    Maybe I'm missing the broader picture, but couldn't a user still
    fiddle with the guts of DB? I mean, couldnt a user do something like

    /*untested code*/
    #include

    int main(void)
    {
    DB *db; /*global structure*/
    db->data="I think I just broke another part of the program";

    return 0;

    }


  5. Re: Why localize structures in this case.

    On Oct 30, 6:21 pm, Chad wrote:
    > Littered through the 10,000 + lines of some Berekely Database code, I
    > keep seeing the following
    >
    > DBHANDLE
    > db_open(const char *pathname, int oflag,,,)
    > {
    > DB *db;
    > /*code*/
    > return(db);
    >
    > }
    >
    > static DB *
    > _db_allocate(int namelen)
    > {
    > DB *db;
    > /*code*/
    > return(db);
    >
    > }
    >
    > char *
    > db_fetch(DBHANDLE h, const char *key)
    > {
    > DB *db=h;
    > /*code*/
    > return(ptr);
    >
    > }
    >
    > The question is, why have
    >
    > DB *db
    >
    > inside the function versus being passed as the formal parameters. Ie,
    > why not have something like
    >
    > static DB *
    > _db_allocate(int namelen, DB *db)


    I don't understand what you're asking. In the case of _db_allocate,
    presumably it is supposed to create a DB object. There is no point in
    passing a DB to it because it doesn't exist yet. _db_allocate has its
    own local variable to store the DB, probably so it can initialize it
    before returning it to the caller.

    But given your other examples, I don't think that was really your
    question. Are you talking about the difference between the use of the
    types 'DB *' and 'DBHANDLE' which appear to be synonomous? That is
    mostly stylistic, and to make it possible to change the object seen by
    the user to something other than a pointer.

    Maybe you could clarify.


  6. Re: Why localize structures in this case.

    Chad wrote:

    > On Oct 30, 6:36 pm, user923005 wrote:
    >> On Oct 30, 6:21 pm, Chad wrote:
    >>
    >>
    >>
    >> > Littered through the 10,000 + lines of some Berekely Database code,
    >> > I keep seeing the following

    >>
    >> > DBHANDLE
    >> > db_open(const char *pathname, int oflag,,,)
    >> > {
    >> > DB *db;
    >> > /*code*/
    >> > return(db);

    >>
    >> > }

    >>
    >> > static DB *
    >> > _db_allocate(int namelen)
    >> > {
    >> > DB *db;
    >> > /*code*/
    >> > return(db);

    >>
    >> > }

    >>
    >> > char *
    >> > db_fetch(DBHANDLE h, const char *key)
    >> > {
    >> > DB *db=h;
    >> > /*code*/
    >> > return(ptr);

    >>
    >> > }

    >>
    >> > The question is, why have

    >>
    >> > DB *db

    >>
    >> > inside the function versus being passed as the formal parameters.
    >> > Ie, why not have something like

    >>
    >> > static DB *
    >> > _db_allocate(int namelen, DB *db)

    >>
    >> > Actually, I've seen this kind of coding move in a lot of C and Unix
    >> > code. I just chose the Berkeley Database Code because I can make
    >> > some heads or tails out of it.

    >>
    >> The idea is to create an abstraction called DBHANDLE used to access a
    >> table.
    >> The reason for doing this is that you do not want the end-users
    >> poking around inside the guts of the DB*.
    >> All they get is some opaque little thingy to reference the table
    >> with. If they start poking around in the innards of the DB*, chances
    >> are good they will break something.
    >>
    >> It is no different than fopen(), fread(), fwrite() passing around a
    >> FILE *.
    >> It's just another way of saying:
    >> "This thing is mine, and as the inventor I know how to use it. If
    >> you
    >> start fiddling with it, we're all going to get into trouble. So
    >> don't touch it."

    >
    >
    > Maybe I'm missing the broader picture, but couldn't a user still
    > fiddle with the guts of DB? I mean, couldnt a user do something like


    He can reasonably do that only if the exact format of DBHANDLE is known.
    The very purpose of opaque types is to hide this information from
    client code.

    Tell me, how would you fiddle with the internals of FILE, other than
    simply stomping all over it?




  7. Re: Why localize structures in this case.

    Chad wrote:
    > Maybe I'm missing the broader picture, but couldn't a user still
    > fiddle with the guts of DB? I mean, couldnt a user do something like
    >
    > /*untested code*/
    > #include
    >
    > int main(void)
    > {
    > DB *db; /*global structure*/
    > db->data="I think I just broke another part of the program";
    >
    > return 0;
    >
    > }


    This program won't compile, because the type 'DB' isn't defined.
    In order for it to compile, you'd have to #include something.
    If the implementer really wants to hide a type, they might not
    put it in the include file; they might just define it only in
    the implementation. Then you'd have to have the source code
    (not just the library) *and* including the wrong header file
    in order to get the type to be defined.

    I'm not sure that the Berkeley DB source code actually does it
    that way, but that's my guess as to what's going on. At least,
    it's one way to achieve it.

    (Of course, you can always redeclare the struct yourself and
    cast it and use that, but if you are *trying* to make your code
    bad, there are lots of ways to do that, and nobody can stop you,
    not even in a bondage-and-discipline, protect-you-from-yourself
    training wheels language.)

    - Logan

  8. Re: Why localize structures in this case.

    On 2007-10-31, Chad wrote:
    >
    > Maybe I'm missing the broader picture, but couldn't a user still
    > fiddle with the guts of DB? I mean, couldnt a user do something like
    >
    > /*untested code*/
    > #include
    >
    > int main(void)
    > {
    > DBHANDLE *db;
    > db->data="I think I just broke another part of the program";
    >
    > return 0;
    > }


    No he couldn't. The idea with opaque types is that DBHANDLE is probably
    defined like:

    typedef void* DBHANDLE;

    Then the definition of the DB structure is not exposed to the user. The
    user just gets a pointer, and uses that to communicate to the library
    which "db" it wants to access. The library now, that knows that these
    pointers are supposed to point to valid DB structs, the declaration of
    which is known internally, just casts the pointer appropriately and uses
    it.

    Example:
    ------------------------ libfoo.h -
    void *create_foo(void);
    void manipulate_foo(void *foo);
    void free_foo(void *foo);

    ------------------------ libfoo.c -
    struct foobar {
    int bar;
    };

    void *create_foo(void)
    {
    struct foobar *f = malloc(sizeof(struct foobar));
    f->bar = 0;
    return f;
    }

    void manipulate_foo(void *foo)
    {
    struct foobar *f = foo;
    f->bar = 31337;
    }

    void free_foo(void *foo)
    {
    free(foo);
    }

    ------------------------ myprog.c -
    #include

    int main(void)
    {
    void *foo = create_foo();
    manipulate_foo(foo);
    free_foo(foo);
    return 0;
    }
    -----------------------------------

    I hope that's clearer now

    --
    John Tsiombikas (Nuclear / Mindlapse)
    http://nuclear.sdf-eu.org/

  9. Re: Why localize structures in this case.

    On Tue, 30 Oct 2007 22:03:54 -0500, Logan Shaw
    wrote:

    >Chad wrote:
    >> Maybe I'm missing the broader picture, but couldn't a user still
    >> fiddle with the guts of DB? I mean, couldnt a user do something like
    >>
    >> /*untested code*/
    >> #include
    >>
    >> int main(void)
    >> {
    >> DB *db; /*global structure*/
    >> db->data="I think I just broke another part of the program";
    >>
    >> return 0;
    >>
    >> }

    >
    >This program won't compile, because the type 'DB' isn't defined.
    >In order for it to compile, you'd have to #include something.
    >If the implementer really wants to hide a type, they might not
    >put it in the include file; they might just define it only in
    >the implementation.


    It's exactly what is commonly done in C++ with the so-called Pimpl
    (Private Implementation), or d-pointer idiom. The idea, again, is
    that those using the header file have no information about the
    internals of ThingPrivate.

    // thing.h
    class ThingPrivate; // Forward declaration
    class Thing {
    private:
    class ThingPrivate* d;

    public:
    Thing(); // Constructor
    ~Thing(); // Destructor
    };


    // thing.cc
    #include "handle.h"

    class ThingPrivate {
    ... // The actual implementation can be anything
    };

    Thing::Thing() : d(new ThingPrivate()) {}

    Thing::~Thing() {delete d;}
    --
    PGP key ID 0xEB7180EC

  10. Re: Why localize structures in this case.

    Keith Willis writes:
    > On Tue, 30 Oct 2007 22:03:54 -0500, Logan Shaw
    > wrote:
    >
    >>Chad wrote:
    >>> Maybe I'm missing the broader picture, but couldn't a user still
    >>> fiddle with the guts of DB? I mean, couldnt a user do something like
    >>>
    >>> /*untested code*/
    >>> #include
    >>>
    >>> int main(void)
    >>> {
    >>> DB *db; /*global structure*/
    >>> db->data="I think I just broke another part of the program";
    >>>
    >>> return 0;
    >>>
    >>> }

    >>
    >>This program won't compile, because the type 'DB' isn't defined.
    >>In order for it to compile, you'd have to #include something.
    >>If the implementer really wants to hide a type, they might not
    >>put it in the include file; they might just define it only in
    >>the implementation.

    >
    > It's exactly what is commonly done in C++ with the so-called Pimpl
    > (Private Implementation), or d-pointer idiom. The idea, again, is
    > that those using the header file have no information about the
    > internals of ThingPrivate.


    And this is A Really Stupid Idea[tm], because the only effect it
    actually accomplishes is making use of a symbolic debugger harder,
    which can then no londer display the contents of such an object, eg to
    determine if some unrelated code may have overwritten it.

    To document something as 'not intended for general use by unrelated
    code' (may your blood be on your hands otherwise) achieves the same
    amount of 'protection', ie it informs users of the code that they
    should not have a reason to mess with the 'protected something' and
    are on their own if they nevertheless try[*], but does not hide
    information from them they could use to debug their own code.
    [*] 'Member X of our team gives a ****' is a social problem
    which cannot really be solved this way.

  11. Re: Why localize structures in this case.

    On Tue, 30 Oct 2007 18:59:50 -0700, Chad wrote:
    > On Oct 30, 6:36 pm, user923005 wrote:
    >> The idea is to create an abstraction called DBHANDLE used to access a
    >> table. The reason for doing this is that you do not want the
    >> end-users poking around inside the guts of the DB*. All they get is
    >> some opaque little thingy to reference the table with. If they start
    >> poking around in the innards of the DB*, chances are good they will
    >> break something.

    >
    > Maybe I'm missing the broader picture, but couldn't a user still
    > fiddle with the guts of DB? I mean, couldnt a user do something like
    >
    > /*untested code*/
    > #include
    >
    > int main(void)
    > {
    > DBHANDLE *db;
    > db->data="I think I just broke another part of the program";
    >
    > return 0;
    > }


    Not really. The database library may have *two* sets of header files:

    - A public interface, which exports and uses only DBHANDLE.

    This is installed (along with static and/or shared objects
    implementing the library on the end-user system.

    - A private header collection, which knows about `DB *' and its
    internals.

    The end-user source code may not have access *at* *all* to the private
    header files, and with a bit of care when designing the API of the
    public header files, it will _not_ need this sort of access.


  12. Re: Why localize structures in this case.

    On Wed, 31 Oct 2007 11:47:34 +0100, Rainer Weikusat
    wrote:

    >Keith Willis writes:
    >> It's exactly what is commonly done in C++ with the so-called Pimpl
    >> (Private Implementation), or d-pointer idiom. The idea, again, is
    >> that those using the header file have no information about the
    >> internals of ThingPrivate.

    >
    >And this is A Really Stupid Idea[tm], because the only effect it
    >actually accomplishes is making use of a symbolic debugger harder,
    >which can then no londer display the contents of such an object, eg to
    >determine if some unrelated code may have overwritten it.


    I fail to see in what way it makes using a symbolic debugger (are
    there any other types these days?) 'harder'. Compile with full debug
    switched on, and link against the debug version of the library
    containing classes Thing and ThingPrivate. It's a well known, well
    used, mature idiom, which actually works and keeps interfaces cleaner.
    IMHO, of course.
    --
    PGP key ID 0xEB7180EC

  13. Re: Why localize structures in this case.

    Keith Willis writes:
    > On Wed, 31 Oct 2007 11:47:34 +0100, Rainer Weikusat
    > wrote:
    >
    >>Keith Willis writes:
    >>> It's exactly what is commonly done in C++ with the so-called Pimpl
    >>> (Private Implementation), or d-pointer idiom. The idea, again, is
    >>> that those using the header file have no information about the
    >>> internals of ThingPrivate.

    >>
    >>And this is A Really Stupid Idea[tm], because the only effect it
    >>actually accomplishes is making use of a symbolic debugger harder,
    >>which can then no londer display the contents of such an object, eg to
    >>determine if some unrelated code may have overwritten it.

    >
    > I fail to see in what way it makes using a symbolic debugger (are
    > there any other types these days?) 'harder'. Compile with full debug
    > switched on, and link against the debug version of the library
    > containing classes Thing and ThingPrivate.


    If a definition of 'ThingPrivate' is not available to the debugger, it
    cannot print its contents.

    > It's a well known, well used, mature idiom, which actually works and
    > keeps interfaces cleaner.


    A similar effect could be achieved by putting the definition in the
    public header file, but define an 'interface class', which contains a
    pointer to an object of the other class/ struct type. Something like:

    struct X_impl {
    /*
    This is for internal use only.
    */
    int a, b, c;
    };

    class X {
    /* methods et. al */

    private:
    struct X_impl *x_impl;
    };

    This way, 'class users' of class X wouldn't need to be recompiled
    when the definition of X_impl changes (this would, of course, break
    'naive' automatically-generated header dependency rules) but
    the information what an X_impl actually is would still be available to
    people who may need to look at objects of this type.


  14. Re: Why localize structures in this case.

    Keith Willis wrote:
    > It's exactly what is commonly done in C++ with the so-called Pimpl
    > (Private Implementation), or d-pointer idiom. The idea, again, is
    > that those using the header file have no information about the
    > internals of ThingPrivate.
    >
    > // thing.h
    > class ThingPrivate; // Forward declaration
    > class Thing {
    > private:
    > class ThingPrivate* d;
    >
    > public:
    > Thing(); // Constructor
    > ~Thing(); // Destructor
    > };


    I can only assume that C++ programmers know about the 'private' access
    modifier and have come up with this idiom anyway. So what are the
    proposed advantages of this over just using the built-in language
    facility? Obviously one can subvert 'private' if you intentionally
    do so, but as I mentioned earlier, personally I don't see value in
    attempting to stop people who are willfully writing bad code.

    - Logan

  15. Re: Why localize structures in this case.

    Rainer Weikusat wrote:
    > A similar effect could be achieved by putting the definition in the
    > public header file, but define an 'interface class', which contains a
    > pointer to an object of the other class/ struct type. Something like:
    >
    > struct X_impl {
    > /*
    > This is for internal use only.
    > */
    > int a, b, c;
    > };
    >
    > class X {
    > /* methods et. al */
    >
    > private:
    > struct X_impl *x_impl;
    > };
    >
    > This way, 'class users' of class X wouldn't need to be recompiled
    > when the definition of X_impl changes (this would, of course, break
    > 'naive' automatically-generated header dependency rules) but
    > the information what an X_impl actually is would still be available to
    > people who may need to look at objects of this type.


    I would find code that uses this idiom to be confusing because it
    would imply that the data members are part of the implementation
    but the methods aren't part of the implementation.

    If you really want to hide the implementation, and you can afford
    overhead of stuff like referring to all data members through an extra
    pointer dereference (your 'x_impl' in this example), it seems cleaner
    to just put an abstract class in the header file as the interface
    and then subclass that in the implementation. Then the users of the
    class wouldn't have visibility into the implementation because they
    wouldn't even know the name of the class that contains the implementation!
    Of course this would force you to hide object creation as well with
    a factory method or something similar since you can't call a constructor
    without knowing the type name in C++, but that might be a good thing in
    a lot of cases and a neutral thing in many other cases.

    - Logan

  16. Re: Why localize structures in this case.

    On Wed, 31 Oct 2007 20:31:41 -0500, Logan Shaw wrote:

    > Keith Willis wrote:
    >> It's exactly what is commonly done in C++ with the so-called Pimpl
    >> (Private Implementation), or d-pointer idiom.

    [...]
    > I can only assume that C++ programmers know about the 'private' access
    > modifier and have come up with this idiom anyway. So what are the
    > proposed advantages of this over just using the built-in language
    > facility?


    Not that I like C++, but if this isn't obvious then it's easy to find
    IMO:

    http://en.wikipedia.org/wiki/Pimpl

    --
    James Antill -- james@and.org
    C String APIs use too much memory? ustr: length, ref count, size and
    read-only/fixed. Ave. 44% overhead over strdup(), for 0-20B strings
    http://www.and.org/ustr/

  17. Re: Why localize structures in this case.

    Logan Shaw writes:
    > Rainer Weikusat wrote:


    [someone writing about pimpl in C++]

    >> A similar effect could be achieved by putting the definition in the
    >> public header file, but define an 'interface class', which contains a
    >> pointer to an object of the other class/ struct type. Something like:
    >> struct X_impl {
    >> /*
    >> This is for internal use only.
    >> */
    >> int a, b, c;
    >> };
    >> class X {
    >> /* methods et. al */
    >> private:
    >> struct X_impl *x_impl;
    >> };
    >> This way, 'class users' of class X wouldn't need to be recompiled
    >> when the definition of X_impl changes (this would, of course, break
    >> 'naive' automatically-generated header dependency rules) but
    >> the information what an X_impl actually is would still be available to
    >> people who may need to look at objects of this type.

    >
    > I would find code that uses this idiom to be confusing because it
    > would imply that the data members are part of the implementation
    > but the methods aren't part of the implementation.


    Huh? Methods are supposed to provide an interface to some
    implementation whose details are not intended to matter for ordinary
    uses. So, this would appear (to me at least) to be quite natural.

    > If you really want to hide the implementation, and you can afford
    > overhead of stuff like referring to all data members through an extra
    > pointer dereference (your 'x_impl' in this example), it seems cleaner
    > to just put an abstract class in the header file as the interface
    > and then subclass that in the implementation.


    The point of my posting was actually that the implementation should
    not be hidden because the respective information would be useful for
    'non-ordinary uses', specifically, for debugging unrelated code.

    Having thought about this somewhat since then, I came to a different
    conclusion in this respect: The reason that C++-classes incoroprating
    other classes need to be recompiled when the implementation of those
    other classes changes is that this is a necessary side effect of the
    'wanted' property that the compiler can generate more efficient code
    if access to the data members of the implementation does not need to
    go through an indirection every time. Additionally, this means it is
    up to the 'class users' to decide where and how they want to allocate
    storage for a particular instance of a class they use. This is
    sensible, because the author of the class itself cannot possibly know
    what 'storage requirements' may exist in a particukar situation where
    the class could be used.

    Taking these two issues into account, I would therefore take this one
    step further and state that not only the implementation should not be
    hidden, but additionally, that it is not the business of 'utility
    class writers' to dictate others what compile-time versus run-time
    speed tradeoffs they desire to make or limit what 'storage allocation
    mechanisms' can be used when using a particular utility class, and that
    people, to whom both doesn't matter, should probably consider using a
    'more abstract' language than C++ happens to be.

    > Then the users of the class wouldn't have visibility into the
    > implementation because they wouldn't even know the name of the class
    > that contains the implementation! Of course this would force you to
    > hide object creation as well with a factory method or something
    > similar since you can't call a constructor without knowing the type
    > name in C++, but that might be a good thing in a lot of cases and a
    > neutral thing in many other cases.


    It would be a bad thing for C++ (or for C, were similar things may be
    constructed) because instances of such a class can neither live in the
    ordinary program data segment nor coulde they be stack-allocated.

  18. Re: Why localize structures in this case.

    On Oct 30, 9:33 pm, John Tsiombikas wrote:
    > On 2007-10-31, Chad wrote:
    >
    >
    >
    > > Maybe I'm missing the broader picture, but couldn't a user still
    > > fiddle with the guts of DB? I mean, couldnt a user do something like

    >
    > > /*untested code*/
    > > #include

    >
    > > int main(void)
    > > {
    > > DBHANDLE *db;
    > > db->data="I think I just broke another part of the program";

    >
    > > return 0;
    > > }

    >
    > No he couldn't. The idea with opaque types is that DBHANDLE is probably
    > defined like:
    >
    > typedef void* DBHANDLE;
    >
    > Then the definition of the DB structure is not exposed to the user. The
    > user just gets a pointer, and uses that to communicate to the library
    > which "db" it wants to access. The library now, that knows that these
    > pointers are supposed to point to valid DB structs, the declaration of
    > which is known internally, just casts the pointer appropriately and uses
    > it.
    >
    > Example:


    >
    > I hope that's clearer now
    >


    But why do that? Why not just provide the definition of
    the data type with the library and pass pointers to/from
    it? What is the point of "opaque" types, anyway, other
    than to force you to use the library functions and hence
    not be able to implement easily any extra functionality
    you may want?

    > --
    > John Tsiombikas (Nuclear / Mindlapse)http://nuclear.sdf-eu.org/




  19. Re: Why localize structures in this case.

    On 2007-11-03, mike3 wrote:
    > On Oct 30, 9:33 pm, John Tsiombikas wrote:
    >> No he couldn't. The idea with opaque types is that DBHANDLE is probably
    >> defined like:
    >>
    >> typedef void* DBHANDLE;
    >>
    >> Then the definition of the DB structure is not exposed to the user. The
    >> user just gets a pointer, and uses that to communicate to the library
    >> which "db" it wants to access. The library now, that knows that these
    >> pointers are supposed to point to valid DB structs, the declaration of
    >> which is known internally, just casts the pointer appropriately and uses
    >> it.
    >>

    >
    > But why do that? Why not just provide the definition of
    > the data type with the library and pass pointers to/from
    > it? What is the point of "opaque" types, anyway, other
    > than to force you to use the library functions and hence


    One reason, as you said would be to give the clue that all other fields
    of the structure are implementation details, and the user should use the
    provided functions instead of accessing them directly. Then the
    implementation may change easily, without affecting backwards
    compatibility.

    Another reason would be to keep the namespace clean. The implementation
    might need to use types defined in many other headers, maybe even from
    other libraries, inside that structure.
    Those need not be exposed to the user program, nor the other libraries'
    headers be installed at all, for that program to be compiled.

    > not be able to implement easily any extra functionality
    > you may want?


    I fail to see how you would implement extra functionality, by just
    having the definition of the DB structure in the header file.


    --
    John Tsiombikas (Nuclear / Mindlapse)
    http://nuclear.sdf-eu.org/

  20. Re: Why localize structures in this case.

    On Nov 3, 11:21 am, mike3 wrote:
    > On Oct 30, 9:33 pm, John Tsiombikas wrote:
    >
    >
    >
    >
    >
    > > On 2007-10-31, Chad wrote:

    >
    > > > Maybe I'm missing the broader picture, but couldn't a user still
    > > > fiddle with the guts of DB? I mean, couldnt a user do something like

    >
    > > > /*untested code*/
    > > > #include

    >
    > > > int main(void)
    > > > {
    > > > DBHANDLE *db;
    > > > db->data="I think I just broke another part of the program";

    >
    > > > return 0;
    > > > }

    >
    > > No he couldn't. The idea with opaque types is that DBHANDLE is probably
    > > defined like:

    >
    > > typedef void* DBHANDLE;

    >
    > > Then the definition of the DB structure is not exposed to the user. The
    > > user just gets a pointer, and uses that to communicate to the library
    > > which "db" it wants to access. The library now, that knows that these
    > > pointers are supposed to point to valid DB structs, the declaration of
    > > which is known internally, just casts the pointer appropriately and uses
    > > it.

    >
    > > Example:

    >
    >
    > > I hope that's clearer now

    >
    > But why do that? Why not just provide the definition of
    > the data type with the library and pass pointers to/from
    > it? What is the point of "opaque" types, anyway, other
    > than to force you to use the library functions and hence
    > not be able to implement easily any extra functionality
    > you may want?


    Because the user does not have access to routines which correctly
    manipulate the members.
    Because the structure contains state information that the library
    assumes is preserved.
    Because exposing additional members means additional documentation
    with no added functionality.


+ Reply to Thread