
On Sat, Dec 5, 2009 at 9:20 AM, Dave van Soest <dsoest@xs4all.nl> wrote:
Hi Christian,
Sure, you can come up with and practically use toy systems with a given
linker in a given configuration that have no problem. But when you have complex and.or derived types, or use dynamic linking, it becomes an intractable problem.
Can you name any complex or derived types that wouldn't work?
// this requires that type A is registered before type B struct A { }; struct B { Pointer<A> a; static void Register(Factory &f) { a = f.Create<A>(); } }; ... // this also requires that A is registered before B struct A { }; struct B : DerivesFrom<A> { }; ...
What is wrong with calling functions before main(), if you do it carefully?
Because "doing it carefully" sometimes isn't enough. For example, if you're doing your own memory management (a common motivator for using factories at all), then any allocation done before main() will be using the clib malloc - and before any of your own custom memory allocation systems have been initialised. Then you have to work-around that. Then that becomes a problem because often this allocator has to be guarded against multiple threads, which requires semaphores or other locking structures to be setup, which then have to be done statically, and because of the ordering issue you are back to square one.
The client coder won't get the opportunity to call any function before main() through this library.
This is not true; initialisation code in the registration method will be called before main(), as will anything called from it. Over time you may want to read configuration files or do memory allocation in these pre-main systems. It grows. It gets gnarly. You work-around it. It grows more. Then you get it working, then change linkers and it all breaks again. Other example gotchas are initialisation of logging systems, string pools systems, data-structures with private static pools - basically, pre-main is a bad space in which to try to do anything. If you kept it extremely simple - no allocation, no threading, no file handling, no exceptions, no nested or derived types, and in a known, single development environment then yeah, sure, it can work. But its not portable, doesn't scale, is untestable, and its extremely limited. Oh, its not testable because the use of globals means that you cant create the system, test it and tear it down again in isolation of other systems. The lack of deterministic ordering means that testing is problematic even in the basic cases.
My response to the third problem is, just like the problem itself, yet unknown.
The C machine is not meant to be used this way. It can be used this way, but it invariably results in many subtle problems. This idea has been kicked around by various people and teams going back decades. It has always proven to be a neat idea that doesn't work in the real world. Perhaps it can work; but all I know about are counter-examples.
Thanks. I really appreciate the time you spent on joining the discussion. Indeed you can't dissuade me from continuing this work, but still I really think it's valuable to have a sceptical counterweight to keep me from turning assumptions into beliefs and pointing me at potential problems I haven't really well thought out.
Welcome, Christian.