Git Product home page Git Product logo

Comments (7)

poletti-marco avatar poletti-marco commented on May 1, 2024

You can bind an instantiation of the template, but not the template itself.
A possible alternative is to have a templated get*component function, and
then instantiate that with the desired types (possibly >1).
See:
https://sites.google.com/site/fruitlib/documentation#TOC-Templated-and-parametrized-components

If this doesn't solve the question, can you please explain what are you
trying to do? I.e. what type(s) do you want to be injectable and to which
classes do you want them to be bound to? A non-working example with c++
code using fruit-like methods might also be useful for me to understand
what you're trying to do. Please include both the component function and
the main code constructing and using the injector.
On 29 Oct 2015 4:48 pm, "ven" [email protected] wrote:

Hi,

in the codebase I'm working with, I have a templated class I'm trying to
get injected. Think something like this:

templateclass DAO {
}

I'd like to be able to .bind() this in one of my components, but it seems
I can't find a way to do it. Is there someway to tell Fruit it's going to
be injected with a template argument? Can I absolutely not do this? If so,
any workaround available?

Thanks!


Reply to this email directly or view it on GitHub
#6.

from fruit.

vendethiel avatar vendethiel commented on May 1, 2024

Let's say this is my code:

namespace base {
  template<typename Model>
  class DAO {
    INJECT(DAO());
  };
}

namespace first_component {
  template<typename Model>
  class AugmentedDAO : DAO<Model> {
    INJECT(AugmentedDAO());
  };
}

// then:
namespace model {
  class Article { ... };
}

namespace project {
  class Project {
    ...
    fruit::Component<...> component()
    {
      return fruit::createComponent()
        .bind<base::DAO, first_component::AugmentedDAO>();
    }
  }

  // expecting to get a first_component::AugmentedDAO here
  class Foo {
    INJECT(Foo(base::DAO<Article>));
  };

}

I'd like to be able to inject a first_component::AugmentedDAO in Foo, and it'd be much better if I didn't have to explicitly list all the components (because maybe a detached component will want to use project as a base)

from fruit.

poletti-marco avatar poletti-marco commented on May 1, 2024

You left out quite a lot of types and the injector, so I'm not sure where in what component do you expect all the DAO<T> to AugmentedDAO<T> bindings to happen. Also you showed only 1 get*component. Were you planning to have only 1 get*component method? Or 1 per model class? Or possibly more? It's not clear.
Note that AugmentedDAO is not a type (only a template) so somewhere in the code it must be instantiated. In what component do you expect such an instantiation to occur? (ok, above you only have 1 component but I suspect you might want to separate your classes in multiple components somehow)

One possible feature that might help in this case (but that is not part of Fruit ATM) would be to allow you to specify a trait-like class describing your templated binding, e.g.:

template <typename T>
struct DAOResolver;

// This is basically a map from DAO<T> to AugmentedDAO<T>
template <typename T>
struct DAOResolver<DAO<T>> {
typedef AugmentedDAO<T> type;
};

and then have a new method in Fruit's PartialComponent class so that you can use that like:

fruit::Component<FooInterface> getFooComponent() {
return createComponent()
// This binding requires a DAO<Article>
.bind<FooInterface, Foo>()
// This allows to resolve the DAO<Article> to AugmentedDAO<Article> so now there's an
// AugmentedDAO<Article> required (but that's fine since it has a default constructor).
// So all bindings can be resolved.
.bindResolver<DAOResolver>()
}

However this bindResolver() would be needed in all components where you need some binding DAO<T> -> AugmentedDAO<T>, so they'd need to include the definition of DAOResolver which in turns needs the definition of AugmentedDAO to be included (and all the things needed for its implementation).
So it won't buy you much IMO, it would be just more concise than all individual bindings, but would not decrease coupling.
In a medium to big system I would expect these deep includes to be an unacceptable issue. Are they ok in your case?

from fruit.

vendethiel avatar vendethiel commented on May 1, 2024

what I have in my "real code" is a connector module, that's agnostic about everything else around, and provides the base DAO. Then I have a versioned "extension" ("first_component" in my example), providing VersionedDAO, that's in another module.

When that module is loaded, its fruit component should replace DAO with VersionedDAO.

Then I have the "application modules", which are not tied together at all, and only have a dependency on the base connector module. They do not know about VersionedDAO, nor should they have to.

Only Fruit should know about the swapping of DAO->VersionedDAO (Well, and the versioning extension), and the application modules should get versioning without knowing about it.

from fruit.

poletti-marco avatar poletti-marco commented on May 1, 2024

When do you expect all the instantiations VersionedDAO, ...,
VersionedDAO to happen?
They must happen in some translation unit where:

  • The definition of VersionedDAO is available
  • The definition of all model classes is available
  • All instantiations are known

If the above 3 are satisfied, Fruit could potentially do it for you, but it
doesn't seem like a scalable way to write your code (you need a place that
has visibility of all those, and the compilation of the resulting
translation unit will increase with your codebase size). Note that separate
compilation of VersionedDAO and the model classes is not possible (this is
how C++ templates work, no way around it).

I'd consider using some kind of non-templated pure virtual interface to
achieve something similar, if you don't need a separate instance of
VersionedDAO to be generated for each model class.
E.g.

class DaoHelper {
public:
virtual void foo() = 0;
};

class V1DaoHelper : public DaoHelper {
public:
virtual void foo() { ... }
};

template
class Dao {
private:
DaoHelper helper;
public:
INJECT(Dao(DaoHelper helper))
: helper(helper) {}

void doStuff() {
...
helper.foo();
...
}
};

class Article {...};

class SomeClass {
private:
Dao

articleDao;

public:
// Injects Dao

, which injects DaoHelper.
// Then you can bind DaoHelper to V1DaoHelper in a get*component function.
INJECT(SomeClass(Dao articleDao))
: articleDao(articleDao) {}

...
};

Then you can have separate compilation (and independent modules) for
V1DaoHelper, the model classes and the classes that need
Dao.
Does this fit your use-case?

from fruit.

vendethiel avatar vendethiel commented on May 1, 2024

Sorry I took so long to answer on this. Your post made me realize quite a few things weren't in place in our codebase, and we refactored it all pretty heavily to have something that works much better. Before, we were using "implicit binding" quite extensively, we've now changed everything to use components.

We ended up using SFINAE on a templated component function, to select one overload (that would .install() another component if X was a subclass of Y).

Thank you!

from fruit.

poletti-marco avatar poletti-marco commented on May 1, 2024

Great, happy to hear that!
Please do let me know if there are other missing features you'd like to see
and we can discuss (just file a bug as you did this time).

On 15 December 2015 at 09:14, ven [email protected] wrote:

Sorry I took so long to answer on this. Your post made me realize quite a
few things weren't in place in our codebase, and we refactored it all
pretty heavily to have something that works much better. Before, we were
using "implicit binding" quite extensively, we've now changed everything to
use components.

Thank you!


Reply to this email directly or view it on GitHub
#6 (comment).

from fruit.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.