Boost logo

Boost :

Subject: Re: [boost] Proposal for Library to perform dependency injection
From: Adam Young (ayoung_at_[hidden])
Date: 2009-10-27 13:15:06


On Tue, 2009-10-27 at 08:52 +0100, Johan Nilsson wrote:
> Adam Young wrote:
> > Having had a career that has bounced me between a few languages, I
> > have had the opportunity to work with a couple of tools in the Java
> > world that didn't see, to have analogues in C++. One of these is the
> > inversion of control containers, of which Spring is one of the best
> > known. Ken Fowler suggested the term "Dependency Injection" as a way
> > to better describe how inversion of control is performed, and I
> > prefer his term.
> >
> > I've written a fairly simple dependency injection framework in C++
> > that seems to make proper use of the C++ Language. It is not
> > attempting to do any COM like component model. Rather, it allows the
> > developer the ability to cleanly separate the Object usage from the
> > construction policy.
> >
> > I've posted the code on Sourceforge at
> > https://sourceforge.net/projects/cpp-resolver/. I have not yet taken
> > the time to get it into proper format for a Sandbox project, but will
> > do that next if there seems to be enough interest in the project. I
> > wrote up the philosophy behind the design here:
> >
> > http://adam.younglogic.com/?p=146
> >
> > The code is currently g++ only, although I've attempted to use only
> > core language constructs. It has no dependencies on other libraries
> > other than stl collections.
> >
> > Any constructive feed back will be most appreciated.
>
> I've been using "manual" DI (mostly constructor-based injection) for a long
> time in C++, and would be interested in a generic DI framework. If it could
> be made to work with dynamically loaded classes it would be even better -
> perhaps with a little help from the proposed Boost.Plugin library that was
> under development some time ago.
>
> That being said, you'll need to provide some more documentation in order for
> at least me to have any specific comments. Starting out with some more
> snippets and examples would be a great idea, IMHO.
>

The code is currently structed as a header only.

https://cpp-resolver.svn.sourceforge.net/svnroot/cpp-resolver/TRUNK/include/resolver.h

The sourceforge svn repo has the sample code checked in here:

https://cpp-resolver.svn.sourceforge.net/svnroot/cpp-resolver/TRUNK/examples/simple/

Sorry that I didn't make the clearer.

> Some desired functionality off the top of my head:
>
> - Simple registration, preferably in some declarative (instead of
> imperative) way.

This is my goal. The idea is the registration happens prior to calling
main. I've used some macros to simplify:
For example:

#define REGISTER(CLASS) \
  bool register##CLASS(){ \
    supply<CLASS>::configure(); \
    return true; \
  } \
  static bool __registered##CLASS = register##CLASS()

This version registers a class with a default factory...bascially a
noargs constructor, and is cleaned up by a destructor call. I'm adding
more macros like these as I need them. They are listed at the bottom of
the header file.

> - Allow e.g. manual, thread-specific, stack-based (see below as well) and
> global registration. Consumers should not need to be aware of which one they
> are using.

Yes, this is supported. Part of my approach was to try and allow the
application developer the flexibility to define their own hierarchy.
Thus, only the global scope is explicitly defined, but you can define
other scopes that make sense to your application, and means of
navigation from one to another.

Component resolution is done from smallest to larges scope, so if you
just have thread local and global, the fetch would attempt to resolve
thread local first, and then global. See this code, which is the heart
of the process.

static T* fetch(Zone& zone){
      Zone* zonep = &zone;
      T * val = object_map[zonep];
      if (!val){
        
        activator<T> act = activator_map[zone.zoneType];

        if (0 == act.factory_) {
          if (zone.parent_){
            return fetch(*zone.parent_);
          }else{
            std::string message
              ("No factory function registered and no parent for ");
            message.push_back( Which );

            throw std::logic_error(message);
          }
        }
        //This needs a lock in order to be thread safe.
        {
          val = (*act.factory_)(zone);
          object_map[&zone] = val;

          destroyer* d = new TDestroyer(&zone);
          zone.push_destroyer(d);
        }
      }
      return val;
    }

> - It should be possible to specify fallback/priority policies; e.g.
> stack-based -> thread-specific -> global.
> - Support for temporarily overriding resolvers; e.g. scoped_resolver<T,
> ...>. Allows for easier test case development, among other things.
> - Support for injecting specific instances as well as types/factories.

Interesting. I hadn't thought of that. That would only resolve in a
specific scope?

>
> Regards,
> Johan Nilsson
>
>
> _______________________________________________
> Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk