Please explain: Pimpl

What’s Pimpl ??? it’s everywhere in the Juce code. What does it stand for, and what does it do?

https://en.wikibooks.org/wiki/C%2B%2B_Programming/Idioms#Pointer_To_Implementation_.28pImpl.29

It means that the class defines more or less only an interface and hides the implementation behind the pimpl pointer. This way you can provide binary compatibility and still change the implementation and it’s member variables.

2 Likes

ah cheers, i had wrongly assumed it was Juce specific.

After learning about pIMPL, why is it used throughout juce? The majority of reasons to involve pIMPL are along the lines of “I’m distributing a compiled binary and a header file and I don’t want people to know how my library works”. aka the true means of making class implementation private. Since JUCE is open-source, what’s the point? The only thing that should be pIMPL in JUCE should be the authorization for ProJucer to use the LiveCompile feature.

It is most often used in juce for platform specific implementations of classes. It allows a different pimpl to be provided for each platform and avoids system specific headers and classes getting pulled into the juce headers.

1 Like

Also used to break cyclic dependencies between classes.

You’ll also see it referred to as a ‘compiler firewall’ – it’s also frequently seen in very large codebases as a way of reducing compile times – when you e.g. change private member variables in a header file, everything including that header file will be recompiled as a result (modulo things like precompiled headers, etc). pImpl lets you hide those private members from the rest of the world. See these great old Herb Sutter pieces on the technique:

http://www.gotw.ca/publications/mill04.htm
http://www.gotw.ca/publications/mill05.htm

what is a ‘cyclic dependency between classes’?

If class A aggregates a member of class B, and class B aggregates a member of type A.

If the aggregation is done with pointers (on the heap), it can be solved via forward declaration.
If the aggregation needs to be done on the stack, it is not solvable, because to determine the size of class A the complete declaration of class B is needed, which is incomplete unless it can count the size of it’s member class A.

On the heap:

class A;
class B;

class A {
    B* myB;
};
class B {
    A* myA;
};

vs. on the stack:

class A {
    B myB;  // B is not declared, cannot allocate space for A, which includes B
};
class B {
    a myA;
};

N.B. you can have the same issue with inheritance, which is even more obvious:

class A inherits B, which inherits A… (and I am not aware that there would be a solution for that)

N.B. 2: in this context: I think the comment to use PIMPL to avoid cyclic dependencies would rather be using aggregation over inheritance…

2 Likes

One more usage of the pimpl idiom in libraries is making it impossible to access internals in child classes. It completely hides the class structure and private methods from the outside and therefore it’s not possible to reliably access internals even using hacks. This has bitten me in the past when I tried subclassing the Slider class in Juce that also uses pimpl for some reason that really is unclear to me.

I do use pimpl in my code to use Boost things with Juce. Boost adds a large overhead to the preprocessor during compilation due to templates and using pimpl I can at least restrict that overhead to just the classes that need boost stuff. The same goes for any largish template based library (eigen comes to mind) and IMHO it’s needed as long as we can’t use precompiled headers with Juce.

1 Like