Boost logo

Boost :

Subject: Re: [boost] Is there any interest in a dependency injection library?
From: Krzysztof Jusiak (krzysztof_at_[hidden])
Date: 2014-07-25 15:47:48


Hi Sohail,

>Definitely interested and will send more comments and questions in a few
days
Thank you for the interest in the library and looking forward for your
comments and questions.

>Immediately though: is it possible to separately compile modules and/or
the configuration?
Yea, it is possible, IMHO the easiest way will be to take advantage of type
erasure here, but Pimpl idiom might be - with a bit of effort - achieved as
well.
So, let's say we want to create application - app - using DI and
configuration specified in module - cpp file.

###app.hpp
class app {
public:
    app(std::shared_ptr<ilogic>, std::shared_ptr<ilogger>);
    int run();

private:
    std::shared_ptr<ilogic> logic_;
    std::shared_ptr<ilogger> logger_;
};

To achieve that with type erasure we are going to declare dynamic_injector
which will be able to create app for us.

###dynamic_injector.hpp
template<typename T>
class dynamic_injector {
public:
    template<typename TInjector>
    dynamic_injector(const TInjector& injector)
        : injector_(new TInjector(injector))
        , f_([&]{ return static_cast<TInjector*>(injector_.get())->template
create<T>(); })
    { }

    T create() const { return f_(); }

private:
    unique_ptr<void> injector_;
    function<T()> f_;
};

Having dynamic_injector in place we won't need any information in module
header file except forward declaration of app.
In module cpp file we include all required dependencies, create
configuration and return dynamic_injector.

###module.hpp
#include "dynamic_injector.hpp"
class app; // forward declaration

class module {
public:
    dynamic_injector<app> configure() const;
};

###module.cpp
#include "module.hpp"
#include "logic.hpp" // include in cpp is okay
#include "logger.hpp" // include in cpp is okay

namespace di = boost::di;

dynamic_injector<app> module::configure() const {
    return di::make_injector(
        di::deduce<logic>() // or di::bind<ilogic, logic>()
      , di::deduce<logger>() // or di::bind<ilogger, logger>()
    );
}

Right now we just have to create our module and create app in main - yea,
we limited ourselves to create only app types,
but actually it is a good thing in general, because then we are forced to
apply composition root.
Anyway nothing is stopping us from making dynamic_injector with type list
instead as well.

###main.cpp
#include "module.hpp"
#include "app.hpp"

int main() {
auto injector = module().configure();
return injector.create<app>().run();
}

Hope this example was helpful and answer your really valid question.

>You linked to my library and one of the insights you have made in yours is
that 99.999999999% of the time, the types are actually decided at
compile-time whereas in mine, it is always at runtime >
>(yuck). So good job on that.
Thank you, that was one of my main goals whilst designing the library -
"Prefer compile- and link-time errors to run-time errors".

Kris

On Fri, Jul 25, 2014 at 1:58 PM, Sohail Somani <sohail_at_[hidden]>
wrote:

> On 2014-07-24, 3:47 PM, Krzysztof Jusiak wrote:
>
>> Hi,
>>
>> Is there any interest in a C++03/C++11/C++14 header only, type safe,
>> library providing compile time, macro free *constructor dependency
>> injection <http://en.wikipedia.org/wiki/Dependency_injection>*?
>>
>
> Hi Krzysztof,
>
> Definitely interested and will send more comments and questions in a few
> days. Immediately though: is it possible to separately compile modules
> and/or the configuration? From what I can tell, the injector is all
> compile-time, which is actually really great *but* it seems like it
> requires you to #include everything in one place which can wreak havoc on
> productivity, ironically. For example, I have ~800 lines of binding code,
> factored into different files and recompiling all those headers + the
> template-heavy binding code every time I change one header somewhere else
> is pointless.
>
> You linked to my library and one of the insights you have made in yours is
> that 99.999999999% of the time, the types are actually decided at
> compile-time whereas in mine, it is always at runtime (yuck). So good job
> on that.
>
> Thanks for doing this, now I don't have to! :)
>
> Sohail
>
>
>
> _______________________________________________
> 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