diff --git a/research/try.cpp b/research/try.cpp index 535ba99f4..f8190b934 100644 --- a/research/try.cpp +++ b/research/try.cpp @@ -49,9 +49,11 @@ typedef unsigned int uint; #include "lib/depend.hpp" #include "lib/depend2.hpp" //#include "lib/meta/util.hpp" +#include "lib/test/test-helper.hpp" #include "lib/util.hpp" -//#include +#include +#include #define SHOW_TYPE(_TY_) \ @@ -61,19 +63,9 @@ typedef unsigned int uint; using lib::ClassLock; +namespace error = lumiera::error; -template -class DependencyFactory - { - public: - static void - build (SRV*& instance) - { - UNIMPLEMENTED ("how to access the per-type factory"); - } - }; - template @@ -82,7 +74,10 @@ class DependInject; template class Depend { + using Factory = std::function; + static SRV* instance; + static Factory factory; friend class DependInject; @@ -91,24 +86,81 @@ class Depend operator() () { if (!instance) - { - ClassLock guard; - - if (!instance) - DependencyFactory::build (instance); - } + retrieveInstance(); ENSURE (instance); return *instance; } + + private: + void + retrieveInstance() + { + ClassLock guard; + + if (!instance) + { + if (!factory) + { + static SRV singleton{}; + instance = &singleton; + factory = disabledFactory; + } + else + instance = factory(); + } + } + + static SRV* + disabledFactory() + { + throw error::Fatal("Service not available at this point of the Application Lifecycle" + ,error::LUMIERA_ERROR_LIFECYCLE); + } }; + template SRV* Depend::instance; +template +typename Depend::Factory Depend::factory; + + +int checksum = 0; + +template +struct Dummy + : boost::noncopyable + { + Dummy() { checksum += N; } + ~Dummy() { checksum -= N; } + + int + probe() + { + return N * checksum; + } + }; + + int main (int, char**) { + Depend> dep11; + Depend> dep5; + Depend> dep12; + + cout << "Siz-DUM : " << lib::test::showSizeof(dep11) << " " << lib::test::showSizeof(dep5) << endl; + cout << "check-vor="< -
+
//Access point to dependencies by-name.//
 In the Lumiera code base, we refrain from building or using a full-blown Dependency Injection Container. A lot of FUD has been spread regarding Dependency Injection and Singletons, to the point that a majority of developers confuses and conflates the ~Inversion-of-Control principle (which is essential) with the use of a ~DI-Container. Today, you can not even mention the word "Singleton" without everyone yelling out "Evil! Evil!" -- while most of these people just feel comfortable living in the annotation hell.
 
@@ -1940,6 +1940,30 @@ Our DependencyFactory satisfies the following requirements
 * in the simplest (and most prominent case), //nothing// has to be done at all by anyone to manage that lifecycle. By default, the DependencyFactory creates a singleton instance lazily in static memory on demand and ensures thread-safe initialisation and access.
 * we establish a policy to ''disallow any significant functionality during application shutdown''. After leaving {{{main()}}}, only trivial dtors are invoked and possibly a few resource handles are dropped. No filesystem writes, no clean-up and reorganisation, not even any logging is allowed. For this reason, we established a [[Subsystem]] concept with explicit shutdown hooks, which are invoked beforehand.
 * the DependencyFactory can be re-configured for individual services (type names) to refer to an explicitly installed service instance. In those cases, access while the service is not available will raise an exception. There is a simple one-shot mechanism to reconfigure DependencyFactory and create a link to an actual service implementation, including automatic deregistration.
+
+!!!Configuration
+The DependencyFactory and thus the behaviour of dependency injection can be reconfigured, ad hoc, at runtime.
+Deliberately, we do not enforce global consistency statically (since that would lead to one central static configuration). However, a runtime sanity check is performed to ensure configuration actually happens prior to any use, which means any invocation to retrieve (and thus lazily create) the service instance. The following flavours can be configured
+;default
+:a singleton instance of the designated type is created lazily, on first access
+:define an instance for access (preferably static) {{{Depend<Bla> theBla;}}}
+:access the singleton instance as {{{theBla().doIt();}}}
+;singleton subclass
+:{{{DependInject<Bla> = Singleton<SubBla>}}}
+:causes the dependency factory {{{Depend<Bla>}}} to create a {{{SubBla}}} singleton instance
+;attach to service
+:{{{DependInject<Bla>{ServiceInstance<SubBla>} }}}
+:* build and manage an instance of {{{SubBla}}} in heap memory immediately (not lazily)
+:* configure the dependency factory to return a reference //to this instance//
+:* the {{{DependInject<Bla>}}} instance itself acts as lifecycle handle (and managing smart-ptr)
+:* when it is destroyed, the dependency factory is automatically cleared, and further access will trigger an error
+;support for test mocking
+:{{{DependInject<Bla> mock{Local<SubBla>} }}}
+:temporarily shadows whatever configuration resides within the dependency factory
+:the next access will create a (non singleton) {{{SubBla}}} instance in heap memory and return a {{{Bla&}}}
+:the  {{{DependInject<Bla>}}} again acts as lifecycle handle and smart-ptr to access the {{{SubBla}}} instance like {{{mock->doItSpecial()}}}
+:when this handle goes out of scope, the original configuration of the dependency factory is restored
+
 
diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm index 7317223ce..7ae326b65 100644 --- a/wiki/thinkPad.ichthyo.mm +++ b/wiki/thinkPad.ichthyo.mm @@ -26694,7 +26694,7 @@ - + @@ -26723,6 +26723,7 @@ + @@ -26777,16 +26778,244 @@ - + - + + + + + + + + + + + + + + + + + + + +

+ ...d.h. Service-Zugang wird automatisch geschlossen, +

+

+ wenn die DependInject-Instanz stirbt +

+ + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+ aber Lebenszyklus ist an die Factory gebunden +

+ + +
+
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+ Folgendes Szenario ignorieren wir: +

+
    +
  • + eine Dependency ist als Service konfiguriert +
  • +
  • + für einen Testmock wird eine Local-Konfiguration darübergelegt +
  • +
  • + der Service wechselt seinen Lebenszyklus-Status (aktiv/inaktiv) +
  • +
+

+ ⟹ der Service zerschießt den Local, oder der Local restauriert am Ende den bereits toten Service. +

+

+ Har Har Har! Selber schuld wer sowas macht. +

+ + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +