Git Product home page Git Product logo

Comments (5)

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

Could you please provide more information on your use case? Let's start with:

  • Is this production code, or are part of it test code? If so, which ones?
  • Is ImplParent an abstract class? (i.e., does it have any non-implemented virtual methods?)
  • Is ImplParent only used as a base class for ImplChild (and possibly other derived classes), or are there any other places that use ImplParent?
  • Is deriving from ImplParent an implementation detail of ImplChild, or are users of ImplChild allowed to know (and depend on the fact) that ImplChild is an ImplParent?
  • If you drew a UML component diagram including {Interface,Impl}{Child,Parent} and the components directly using those, how would it look like? (note that multiple classes/interfaces might be in the same UML component, e.g. if ImplParent is only an implementation detail of ImplClient.) The relationships between Fruit components are closely tied to how your component diagram looks like.

from fruit.

vendethiel avatar vendethiel commented on May 1, 2024

Is this production code, or are part of it test code? If so, which ones?

Production code. What's missing, however, is the diamond. It technically looks like this.

struct InterfaceParent {};
struct ImplParent : virtual InterfaceParent {};

fruit::Component<InterfaceParent> getParent() {
 return fruit::createComponent()
    .install(...)
    .install(...)
    .install(...)
   .bind<InterfaceParent, ImplParent>();
}

struct InterfaceChild : virtual InterfaceParent {};
struct ImplChild : InterfaceChild, ImplParent {};
fruit::Component<InterfaceChild> getChild() {
 return fruit::createComponent()
   .useInstallsFrom(getParent()) // ??? is it possible to do something like this?
  .bind<InterfaceChild, ImplChild>();
}

Is ImplParent an abstract class? (i.e., does it have any non-implemented virtual methods?)

No, the parent is standalone, and can itself be injected. In this case, it's ImplParent that's used.

Is ImplParent only used as a base class for ImplChild (and possibly other derived classes), or are there any other places that use ImplParent?

Is deriving from ImplParent an implementation detail of ImplChild, or are users of ImplChild allowed to know (and depend on the fact) that ImplChild is an ImplParent?

Only used there. It's supposedly an implementation detail.

If you drew a UML component diagram

I've never done UML, sorry.


To summarize a bit on the issue, I'll take a real-world use case.

Let's say I have a "BaseModel" interface. It has a "BaseModelImpl". (Which it binds to. The impl is obviously an implementation detail). That's for the library part.

Now, I want to extend it in my application, and I'd like to have a TimestampableModel, which has a method touch on it, that updates the timestamps. The Impl class is TimestampableModelImpl.

Since we don't want to redefine every single method that BaseModel exposes in TimestampableModelImpl (i.e. by injecting the BaseModel in TimestampableModelImpl, then redefining every method to forward to BaseModel), we directly inherit BaseModelImpl in TimestampableModelImpl. It's all an implement detail – whoever injects TimestampableModel (the interface) needn't care about how they're implemented.

from fruit.

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

Since the user of such a library (who writes TimestampableModelImpl) needs to have access to the definition of BaseModelImpl (not just to have access to a BaseModel object that happens to be a BaseModelImpl) BaseModelImpl must be exposed in the library's public interface, you can't just hide that definition in a cpp file as you'd normally do with *Impl classes when using Fruit.

You could do sth like:

// base_model.h
struct BaseModel {...};
fruit::Component<BaseModel> getBaseModelComponent();

// base_model_impl.h
// This is a *public* header, even though it has an _impl suffix!
#include "base_model.h"
struct Foo;
struct Bar;
struct BaseModelImpl : public BaseModel {
    INJECT(BaseModelImpl(Foo* foo, Bar* bar)) {...}
    ...
};
// Use this when extending BaseModel
fruit::Component<Foo, Bar> getBaseModelDepsComponent();

// base_model.cpp
#include "foo.h"
#include "bar.h"
#include "base_model_impl.cpp"
... // Implementation of various BaseModelImpl methods
fruit::Component<Foo, Bar> getBaseModelDepsComponent() {
    return fruit::createComponent()
        .install(getFooComponent())
        .install(getBarComponent());
}
fruit::Component<BaseModelImpl> getBaseModelComponent() {
    return fruit::createComponent()
        .install(getBaseModelDepsComponent())
        .bind<BaseModel, BaseModelImpl>();
}

// timestampable_model.h
#include "base_model.h"
struct TimestampableModel : public Model {
    virtual void touch() = 0;
};
fruit::Component<TimestampableModel> getTimestampableModelComponent();

// timestampable_model.cpp
#include "timestampable_model.h"
#include "base_model_impl.h"
#include "baz.h"
struct TimestampableModelImpl : public BaseModelImpl, public TimestampableModel {
    INJECT(TimestampableModel(Foo* foo, Bar* bar, Baz* baz))
        : BaseModelImpl(foo, bar) { ... }
    ....
};
fruit::Component<TimestampableModel> getTimestampableModelComponent() {
    return fruit::createComponent()
        .install(getBaseModelDepsComponent())
        .install(getBazComponent())
        .bind<TimestampableModel, TimestampableModelImpl>();
}

Does this structure achieve what you want?
If you want multiple levels (i.e., if you want to allow a user of the library that exposes TimestampableModel to also be able to inherit from TimestampableModelImpl), you can also have a getTimestampableModelDepsComponent() with a structure similar to the one for base_model, where you make TimestampableModelImpl part of your library's public interface.

from fruit.

vendethiel avatar vendethiel commented on May 1, 2024

Ugh, sorry. I thought we followed up on this. We went with your suggestion in the end, and it's worked well. You can close this issue.

from fruit.

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

Ok, happy to know that it worked for you. Closing this then.

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.