Stuck on errors from bi-directional references between component and other class

Hi folks, I’m trying to make an app with an embedded Scheme interpreter (S7 Scheme), which is the same way the Common Music application “Grace” works. I plan on publishing this as examples for people who want to try out this style of development (running a lisp engine in your C, so fun!). But I’m doing something dumb. I want the interpreter to be wrapped up in an Engine class (not a juce component, plain old cpp class), and to have my MainComponent of my Juce app instantiate this and store a reference to it. This is working fine, engine kicks up the scheme interpreter, all happy.

However, my next step was to pass a reference to the MainComponent to the Engine in its constructor so that the engine class could call back to the MainComponent. Basically the gui pattern I remember from various widget libs I used years ago. So something like the below in the Engine:

class Engine  
{
public:
    Engine(MainComponent *parentComponent)
    {
        // store the reference to the parent juce component so we can callback to it
        parent = parentComponent;

        log("Engine constructor, initing s7");
        s7 = s7_init();
        log("init complete"); 
    }
    ~Engine(){ }

private:
    // pointer to the S7 interpreter      
    s7_scheme *s7;      
    // pointer to the parent Juce component for calling back to it
    MainComponent *parent;  
};

And something like this in the main component constructor:

//==============================================================================
MainComponent::MainComponent()
{
    // init the engine, passing a reference to self to store in the engine component
    engine = new Engine(this);

}

When I do this, I get an error saying "No templated named MainComponent’; did you mean LassoComponent?

And I’m like “what? where did you come from Lasso???”

I could well be doing something dumb in how I’ve laid out my files because I’m super C++ rusty. So I’ve put it in a public repo so you can see the whole thing:

If anyone is able to help that would be awesome.
thanks!

I did something like this a long time ago, but I can’t remember if one needs to use some void pointer kung-fu for those kind of circular references? And I really don’t understand why xcode is giving me messages about No template, instead of just complaining about the pointer. But my C++ memory is all old school.

Engine *engine;
// etc
engine = new Engine(this);

Don’t do that, you’ll have to delete that thing. Use a plain, stack object or a unique_ptr.

MainComponent *parent;

This may be ok because the ownership goes the other way around, so an Engine will always be outlived by its MainComponent -it could also be a reference.

The problem you have here is not the circular reference of objects but of headers. Because MainComponent owns its Engine, you should include engine.h in maincomponent.h, but move all the implementation of Engine to a cpp, and include maincomponent.h there. In engine.h, you predeclare MainComponent with class MainComponent; -you can declare a pointer or a reference to an incomplete class.

btw, I’m not sure about this because I’ve not done standalone apps with Juce, but a Component doesn’t look like the right place to store something like a Scheme interpreter from an MVC point of view -it’s a GUI object.

Hi Laureano, thank you very much for helping me today, I really appreciate it. I’ll try what you say, and that’s exactly the kind of advice I needed (I did order some new C++17 books, but haven’t got through them yet!)

With regard to who owns the engine class, I don’t know that either. I was basing my choice off the way the tutorials seem to have the MainComponent as the main entry point for an applications functionality, but I also haven’t read through all the tutorials yet. I think the engine ought to be a component (in the generic sense) owned by whatever the main application object is. Do you think in this case it should be a member of the Juce application instead? I’m just getting started with this so am happy to drastically re-arrange. I’m basically trying to make a framework that allows me to use as much of the same Scheme code as possible, whether I’m in a Max/MSP object or a Juce App. (I’m the author of Scheme for Max, a newish Max external that brings S7 Scheme to Max/MSP)

thanks again!

1 Like

JUCEApplication looks more like the main application object, but don’t trust me there. In the case of plugins, the main object is usually AudioProcessor -AudioProcessorEditor is the main (GUI) Component, and it’s not supposed to own model-related stuff.