I posted a rather poorly-worded question on today's episode about a tradeoff between persistent data and a simple API. I hope this post makes better sense. Not sure.
I'm programming something in C++ (and yes it uses a nerfed subset of OO design). One of my objectives (inspired by handmade hero) is to keep all code on the stack. I plan for my code to release as a library with a boiled-down, simple API. I don't want the user to do any complex initializations, or hand any empty containers or empty pointers into functions being called. I don't want the user to do any persistence support programming at all, other than to request 1 or 2 initializations per functional facility. The rest of the user experience should be to access high-level functions that give access and control over highly transformed data held and maintained by the library.
The usage scenario is that the tech user can write his or her own driver atop the library, meaning the user controls the main loop of program execution and thus the ownership and persistence of a few top-level objects. I want him/her to focus on their own code, not in maintaining mine.
That's not a problem, until the libraries are called to create complex data structures, usually with nested objects. Some of these data structures need to persist for the lifetime of the user's driver without any maintenance, or even without the user's knowledge.
The problem with doing things entirely on the stack is that although the driver code may possess pointers to top-level objects in a library, the library is responsible for creating and storing fairly complicated multi-level substructures internally. If creation and storage of these items is done on some lower level of the stack, there are only three things I can do to persist them.
1. Require the user to preallocate empty spaces and containers for objects, taking creation ownership of them in the driver. This neither practical or desirable, since it defeats the principle of a simple API, and is in effect pushing responsibility for container creation on the user, making him/her responsible for memory management. Secondly, you can't really know how many of something you will need in dynamic objects, which may contain X number of sub-objects determined by running code at a lower level in a certain context.
2. Using the static keyword at object creation time in the library. This is something like heap programming. You can for example, create a struct instance inside a function and allow it and its pointer to be attached to a container created at the same level using the same technique. This will persist after the initializations have been done on the object. The only drawback is that it lasts for the lifetime of the program.
3. Use the heap. I am trying not to go there.
Persistence of larger internal data structures is something I do not want the user to directly access except through high-level functions and indirection. I generally want to store things at the same level I'm creating and allocating them, and it seems there is no way to do this other than 2 of the 3 ways listed above.
Am I totally not grasping the concepts of top-down creation and allocation here? Am I wrong in thinking the API will suffer if I demand creation be done always at a higher level?
Sorry this was so long...