> If you have a struct which might grow, don’t actually make it part of the ABI, don’t give users any way to find it’s size, and write functions to create, destroy and query it.
Thanks! This is very insightful. What is a solution to this? If I cannot expose structs that might grow what do I expose then?
Or is the solution something like I can expose the structs that I need to expose but if I need to ever extend them in future, then I create a new struct for it?
> What is a solution to this? If I cannot expose structs that might grow what do I expose then?
Option 1: If allocating from the heap or somewhere otherwise fixed in place, then return a pointer-to-void (void *) and cast back to pointer-to-your-struct when the user gives it back to you.
Option 2: If allocating from a pool, just return the index.
Unless I've been wrong all these years in C you can write a header file which says this is a pointer to T, without ever saying what's in T and C will not allow people to access the elements of T, since it doesn't know what they are, but they can have the pointer since it doesn't need to know how T is laid out to know it's a pointer and all pointers are laid out the same in C.
Then for your internal stuff you define what's inside T and you can use T normally.
Also, even if you're returning an index, learn from Unix's mistake and don't say it's an integer. Give it some other type, even if that type is just an alias for a primitive integer type, because at least you are signalling that these are not integers and you might make a few programmers not muddle these with other integers they've got. A file descriptor is not, in fact, a process ID, a port number, or a retry count, and 5 is only any of those things if you specify which of them it is.
> in C you can write a header file which says this is a pointer to T, without ever saying what's in T
What you're referring to is a forward declaration. Forward declarations only work when the definition will be known at some point during compilation.
If you're writing an API header to a binary you're shipping and you don't want to provide the definition to the user of the API, then a forward declaration is no bueno. The compiler needs to know the size, alignment, etc.
No, I don't mean void pointers, I'm talking about just pointers to some unknown type T.
What's inside a T? How can we make one? We don't know, but that's fine since we have been provided with APIs which give us a pointer-to-T and which take a pointer-to-T so it delivers the opacity required.
Thanks! This is very insightful. What is a solution to this? If I cannot expose structs that might grow what do I expose then?
Or is the solution something like I can expose the structs that I need to expose but if I need to ever extend them in future, then I create a new struct for it?