On 2/6/2014 2:16 PM, Jorgen Grahn wrote:
]
Much of the code may just
treat it as an opaque type that is passed from here to there, and sent
to/from functions as needed.
Yes, but then you often want a forward declaration -- if you don't need
the full struct definition and don't want to needlessly pull in header
files.
I don't understand. If you're not using "the full struct
definition" and you're not treating it as an opaque type, just
what are you doing? And, er, how?
I'm treating it as an opaque type -- surely I never said I didn't?
Apparently not. It seems I read more into what you wrote
than you put there. (In American usage, when Speaker A says
"X" and Speaker B responds "Yes, but Y," it usually means that
Y is an objection to X, that B thinks X is wrong in some way.
I misunderstood you as denying that the type was opaque, but it
appears you didn't mean that at all. Sorry!)
Ah, I can see that kind of interpretation now. I should probably have
written "Yes. But then ...".
Not sure why this is needed ...
Seems it's not. Must be some habit I picked up; I don't know when or
where. Based on the warnings gcc shows me, it's needed in a related
situation:
struct bar_lib;
void foo(struct bar_lib*);
Is the example realistic? Perhaps so -- Different programmers
face different demands and address them in different styles, but
this isn't a style I think I'd choose.
It's the usual lesson of c.l.c -- you think you only do what
"everyone" does, and then it turns out they don't.
I should probably admit here that my primary language is C++. It might
be the case that this style is more common there. I didn't bring it
up because it seemed the languages worked the same in this area
(except you can refer to 'struct Foo' as just 'Foo').
Why expose the fact that
foo depends on bar? That is, why reveal the `struct bar_lib*'
nature of `impl' to a user of "foo.h"? Considerations:
- If the user is to use `impl' to get at the innards of the
`struct bar_lib', he'll need to include "bar_lib.h" anyhow and all
this name-hiding is for naught. Even if `struct bar_lib' remains
opaque but the user knows he can use the `impl' element to call
bar_lib's functions he'll need "bar_lib.h" for their declarations.
True. So this isn't the reason. If all users of foo.h will want
bar_lib.h too, the forwarding above is pointless. The assumption above
is that users will want to deal with Foo objects, but probably not
mess with the struct bar_lib.
'impl' was a badly chosen name -- it makes it sound as if struct Foo
is just a wrapper for a struct bar_lib. I think it's more realistic
to assume struct Foo contains a bunch of immediately useful elements,
/and/ this opaque handle.
By the way, I now realize a much clearer and simpler example would
have been something like this:
// serialize.h
struct in_addr;
struct in6_addr;
struct Foo;
int serialize_addr(char* buf, size_t len, struct in_addr val);
int serialize_addr6(char* buf, size_t len, struct in6_addr val);
int serialize_foo(char* buf, size_t len, struct Foo val);
// ...
- If the user treats `struct bar_lib' as opaque *and* doesn't
call any bar_lib functions directly (but always goes through foo),
then `impl' can be of any struct pointer type at all (because all
struct pointers smell the same), although this might lead to a lot
of tedious cast operators in the implementation of foo. `impl'
could even be a `void*', at the expense of a tiny amount of type
safety.
Yes, although I value my type safety and try to stay clear of void*.
- When opacity is one of the goals, I usually find it better
to keep `struct Foo' opaque and have my foo_create() function return
a pointer to a newly-allocated `struct Foo' rather than a completed
instance thereof. That way I need reveal nothing whatsoever about
bar_lib, and am free to adopt the improved xbar_lib without disturbing
foo's clients.
This is why I shouldn't have used the name 'impl' in the example. Yes,
if the contents of struct Foo are entirely uninteresting to its
clients, I would probably make it opaque, too.
Finally, I still don't see what this has to do with "forward
declarations" or with typedefs -- the string `typedef' is entirely
absent from the example ...
Yes, absent it is. I should have made the purpose of the example more
clear. My question was "could I have done this without knowing the
struct tag bar_lib?" and "how would knowing a typedef for it have
helped me?"
/Jorgen