Comments (5)
Hi,
although I think it is possible, I also think it would break the idea of having a single point of configuration per app. The purpose of the container is just to spare you the cost of wiring your stuff by yourself.
Why is the shared_ptr
reference counter overhead so costly to you? In what particular case do you have to let the container build your app's components and then move the components around?
I can either try to understand and help you out or I can suggest you to have a look to another IOC container which supports what you are asking for (but it is a static one).
Tell me
from hypodermic.
Hi again,
What concerns me with shared_ptr is less the performance or memory overhead and more the question of ownership and destruction time. When there is shared ownership, one can never be sure when the object in use will be destructed.
In my use case, I have a family of classes that optionally may use some service. The service is represented as another class (let's call it "Service"), and each instance in the family is initialized with its own instance of Service, which may be null or injected from outside. The expected behavior is that the Service instance will be destructed with the containing class.
class Service;
class FamilyBase
{
public:
// some_ptr may be shared or unique
FamilyBase(some_ptr<Service> && servicePtr) : mServicePtr(std::move(servicePtr)) { }
private:
some_ptr<Service> mServicePtr;
};
While Hypodermic can inject a shared_ptr with use count of 1 to the FamilyBase constructor, there is no built-in constraint against injection of a shared_ptr with a larger reference count. For example, if I decide to inject the dependency manually, I can inject a shared_ptr with any reference count.
On the other hand, a unique_ptr ensures a binary state of the "reference count", and I can be sure that the Service instance will, indeed, be destructed when FamilyBase is destructed.
As to your suggestion to look at Boost.DI - our group has examined it in the past. At the time, it did not support dynamic runtime registration of new types, which was a critical feature for our project. We communicated with the author, who said that he added such a feature following our request. It's indeed very kind, but we did not want to take the risk of using a completely fresh feature, so we fell back to Hypodermic.
With this said, I wanted to raise another question about resolving non-shared_ptr values. Specifically, I want to have a class whose constructor takes some parameters from Hypodermic and other parameters from the caller. I don't expect the current resolve
method to address this. But I wonder if it's possible to design some generic form for this operation.
Here's an example, somewhat artificial and contrived, but shows the direction.
class Logger
{
public:
Logger(std::string const & name);
};
void foo()
{
// define builder, container, etc.
// now I want to resolve<Logger> and somehow pass the name in the same call/line.
}
I know that it's possible to create a nested container where a specific instance is registered as string
and resolve from that container. However:
- It is quite inconvenient syntactically to go through all this more-or-less boilerplate stuff just to get a string in the end.
- When I get the string, I can only get it as shared_ptr, which is yet another unnecessary overhead.
- Worse of all, if there are several such parameters, I must register all of them, and if the same type repeats more than once, I must use an ever more complicated form of register just to get to something essentially simple.
Let's make the example a little more interesting to enhance the discussion.
class LoggerDependency;
class Logger
{
public:
Logger(std::shared_ptr<LoggerDependency> dependency, std::string const & name);
};
What I am after is some "construct" that would take a string
in this case and do the following imaginary operation.
std::shared_ptr<Logger> myLoggerCreator(std::string const & name)
{
// imagine that container is defined somewhere
auto dependency = container.resolve<LoggerDependency>();
return std::make_shared<Logger>(std::move(dependency), name);
}
But I want this in generic form, so I would not have to manually write this for each resolved product and each parameter pack.
Can you think of anything in this direction?
from hypodermic.
I understand you would like the compiler to keep ensuring —statically— the lifetime of your components. I don't know if or when I will rewrite a proper storage so that the container could resolve some unique pointers. For now, you have to configure your components and kind of let the container manage the resources, i.e., single instances will be released when they are no longer used by your app or by the container.
Regarding the injection of basic types instances, you have to provide some factories. I would write something like this:
template <class TProduct>
std::shared_ptr< TProduct > buildProduct(std::string const & name)
{
// resolve something that is either registered or autowirable/registerable on the fly
auto product = container.resolve< TProduct >();
product->configureName(name);
return product;
}
Is this close to what you are looking for?
from hypodermic.
Hi Yohan,
I understand the issue with resolution of unique_ptr. For now, we can stay as it is, but I thought it was at least worth mentioning.
With regards to the basic types, I first want to emphasize that I don't want a configureName
method but to pass the name somehow as part of the construction of the product. As I wrote above, we currently address this by creating a nested container in which the specific values of the basic types are registered, as well as a factory for TProduct
which resolves those arguments by name. It is cumbersome and not very efficient, but it kind of works. Efficiency aside, what I have in mind is something a little like the std::bind
syntax (and I really dislike std::bind
!), which may be a little similar to this:
class Product {
public:
Product(std::shared_ptr<Service> servicePtr, std::string const & name);
};
// here we set up a container that knows how to resolve for Service, at least.
std::shared_ptr<Product> = myResolve<Product>(container, /* maybe some placeholder designation, */
"productName");
where myResolve
takes care of all the mechanics of building the nested container, and finally resolves from it.
I must admit that I always become confused when it comes to the actual semantics of std::placeholders
used in bind
, and I wish that there was a friendlier way to express the true intention of the caller. But for lack of a better tool, I'd use it if it solved the issue.
I do think that it is possible to define a generic function like myResolve
, and, if you had wished, make it part of the library. But here I am just interested in your opinion about the feasibility of such a function and maybe if you have an idea how it can be written.
Regards,
Ofri
from hypodermic.
Hey Ofri,
Hypodermic statically knows what your constructor looks like by the time you are registering its type. When you build the container, it is described to a kind of type erased structure. What you are asking for (if I get it right) is currying and I don't know how to mix up constructor arguments deduction with partial function so that you can fill the gaps later dynamically. This is way easier when everything is static but a static container is template contagious. Again, I may find a way by rewriting the storage but for now, I have no idea to add this feature.
Although I agree that using a nested container for this peculiar use reveals to be cumbersome, mind if I ask what is so wrong about invoking a configureName
method by the time you let the container create your whole component in a factory and then setup some stuff before returning your properly initialized fresh instance? No nested container, just a new method to expose.
from hypodermic.
Related Issues (20)
- GUN C++ 4.7.3 Compiler error HOT 1
- Current syntax for register factory with arguments HOT 5
- Pass parameters to register type HOT 1
- Resolve a chain of instantiate of explicit dependencies name?
- Compile errors: multiple definition of boost::*
- static assertion failed: TArg should be a complete type HOT 5
- [FeatureRequest] Fluent lifetime management HOT 1
- Autowiring of factory methods HOT 2
- Question: register two interfaces for same concrete class HOT 2
- Fail to build in window boost1.7 gcc9
- Bug: interface is resolved twice from nested container if they are added as both .as<interface>() and .asSelf() HOT 2
- Bug: singleInstance not working as expected when resolving from nested containers HOT 2
- How to inject a factory for named instances? HOT 3
- Is it possible to specify the dependency explicitly while resolving HOT 4
- Issue when resolving same types in different shared libraries HOT 1
- ContainerBuilder doesn't have a virtual destructor HOT 1
- Hypodermic 2.5.3 won't link with Boost
- Is there a version without boost HOT 5
- Alternatives to `std::make_shared` HOT 4
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from hypodermic.