Sutter's Pimples: Good, Bad, or Ugly?

S

Steven T. Hatton

Pete Vilder mentioned this a few days back. This is the "Compiler-Firewall
Idiom", or pimple. It's similar to an approach taken in some Java designs.
AAMOF, when I saw it in Java, my first reaction was "Oh by Þor! It's
freakin' headers all over again!"

My greatest misgiving about the approach is that it seems overly
complicated. I /feel/ as if there is a better more 'conventional' way of
dealing with the separation of interface and implementation. OTOH, it's
clear to me that the people who have advocated it are not stupid.*

Here's the discussion: http://www.gotw.ca/publications/mill05.htm

What do you make of it?

*(Sutter does serve the Dark Lord, but that's a different story. Lippman,
too has passed into darkness.)
 
A

Alf P. Steinbach

* "Steven T. Hatton said:
What do you make of it?

Too lazy too look up the discussion -- I was here before that and during
it.

The gist of pimpl is not to separate class interface and implementation, as
you seem to think.

It is to remove a header file dependency. For example, a C header file for a
popular imaging library might use the word "class". And a header file for a
very popular operating system might use all sorts of macros and nasty stuff.

An alternative to pimpl that accomplishes the same basic purpose, but with
a limitation as result, is to declare only an abstract class and a factory
function in the header file.

The limitation is that implementation inheritance is then effectively
disabled; the client code has no access to the declaration of the actual
derived, concrete class that the factory function has as return type.


*(Sutter does serve the Dark Lord, but that's a different story. Lippman,
too has passed into darkness.)

Would you rather have Microsoft stumbling blindly on as before? With the help
of those two the latest version of Visual C++ is one of the most
standard-conforming compilers, at least when disregarding trivial stuff like
being able to use a standard 'main', exceptions and RTTI by default.
Previously it was one of the most non-compliant where even trivial
standard-conforming code would not compile, stranding a large fraction of C++
practitioners in the la-la land of an undocumented ad-hoc company standard.
 
S

Steven T. Hatton

Alf said:
Too lazy too look up the discussion -- I was here before that and during
it.

The gist of pimpl is not to separate class interface and implementation,
as you seem to think.

This may be a question of semantics. The way I see this is similar to the
way the org.w3c.dom language binding is implemented in Java. There is a
set of API abstract classes and interfaces which the client programmer
writes to. Then there is an implementation which can be replaced without
changing the client code. This particular example may actually be closer
to your example of using a factory. Nonetheless, the motivation is the
same.
It is to remove a header file dependency. For example, a C header file
for a popular imaging library might use the word "class".
Imagemagick?

And a header file for
a very popular operating system might use all sorts of macros and nasty
stuff.

I can't imagine. ;-) Hey, that's an advantage of Open Source. I can freely
discuss the design faults, and if people agree, it will eventually be
addressed.
An alternative to pimpl that accomplishes the same basic purpose, but with
a limitation as result, is to declare only an abstract class and a factory
function in the header file.

The limitation is that implementation inheritance is then effectively
disabled; the client code has no access to the declaration of the actual
derived, concrete class that the factory function has as return type.

I'll have to think about this one. I'm not sure about the ease of extending
a class with a pimpl.
Would you rather have Microsoft stumbling blindly on as before? With the
help of those two the latest version of Visual C++ is one of the most
standard-conforming compilers, at least when disregarding trivial stuff
like being able to use a standard 'main', exceptions and RTTI by default.
Previously it was one of the most non-compliant where even trivial
standard-conforming code would not compile, stranding a large fraction of
C++ practitioners in the la-la land of an undocumented ad-hoc company
standard.

So, you are suggesting Sutter and Lippman are leading them from darkness
into the Light?
 
N

Nick Hounsome

Steven T. Hatton said:
Pete Vilder mentioned this a few days back. This is the "Compiler-Firewall
Idiom", or pimple. It's similar to an approach taken in some Java designs.
AAMOF, when I saw it in Java, my first reaction was "Oh by Þor! It's
freakin' headers all over again!"

My greatest misgiving about the approach is that it seems overly
complicated. I /feel/ as if there is a better more 'conventional' way of
dealing with the separation of interface and implementation.

Well come on then - bless us all with your insight.
I don't see how there can logically be a "better more 'conventional' way"
since this IS
the conventional way.
OTOH, it's
clear to me that the people who have advocated it are not stupid.*

Here's the discussion: http://www.gotw.ca/publications/mill05.htm

What do you make of it?

*(Sutter does serve the Dark Lord, but that's a different story. Lippman,
too has passed into darkness.)

--
p->m == (*p).m == p[0].m
http://www.kdevelop.org
http://www.suse.com
http://www.mozilla.org
 
S

Steven T. Hatton

Nick said:
Well come on then - bless us all with your insight.
I don't see how there can logically be a "better more 'conventional' way"
since this IS the conventional way.

You may notice I have '/feel/' emphasized, and ''conventional'' in single
quotes. The intent of the former was to stress that I do not have
a /reasoned/ alternative. The intent of the latter was that I didn't
really mean the CFI (Compiler Firewall Idiom) is unconventional.

What do you see as the motive for it? Do you use it ubiquitously? I'll have
to start examining the headers in some of the programs I have the source
for to see if and how it is used there.
 
P

Phlip

Steven said:
Pete Vilder mentioned this a few days back. This is the "Compiler-Firewall
Idiom", or pimple. It's similar to an approach taken in some Java designs.
AAMOF, when I saw it in Java, my first reaction was "Oh by Þor! It's
freakin' headers all over again!"

My greatest misgiving about the approach is that it seems overly
complicated. I /feel/ as if there is a better more 'conventional' way of
dealing with the separation of interface and implementation. OTOH, it's
clear to me that the people who have advocated it are not stupid.*

"Pimpl" is an idiom that one refactors into existing code to compile faster.

Refactors change design while leaving behavior the same. The Pimpl refactor
leaves logical design the same while tweaking physical design, so
translation units needn't see the details of other classes. That prevents
excessive recompiles when you change a highly reused class.

But Pimpl is for emergencies, after a design is committed. C++ was designed
to permit compilation firewalls based on abstract types; Pimpl abstracts a
concrete type.

Robert C. Martin's "Dependency Inversion Principle" describes this design
goal.

http://www.objectmentor.com/resources/articles/dip.pdf

It implies that only classes with a few pure-virtual methods should be
widely re-used. This is both a valid design technique and a system that, in
C++, prevents runaway re-compiles.
 
D

Daniel T.

Steven T. Hatton said:
Pete Vilder mentioned this a few days back. This is the "Compiler-Firewall
Idiom", or pimple. It's similar to an approach taken in some Java designs.
AAMOF, when I saw it in Java, my first reaction was "Oh by Þor! It's
freakin' headers all over again!"

My greatest misgiving about the approach is that it seems overly
complicated. I /feel/ as if there is a better more 'conventional' way of
dealing with the separation of interface and implementation. OTOH, it's
clear to me that the people who have advocated it are not stupid.*

Here's the discussion: http://www.gotw.ca/publications/mill05.htm

What do you make of it?

The only time I have used the pimpl idiom is when I need compile time
polymorphism. For example when I have a class that is implemented
completely differently for two different architectures but have the same
interface. I will have one header file, and two (or three) source files
for the class. (Foo.h, FooCommon.cpp, FooMac.cpp, FooWindows.cpp for
example) This allows all programs to use the same header even though the
two architectures use completely different internal variables and
implementations.
 
N

Nick Hounsome

Steven T. Hatton said:
You may notice I have '/feel/' emphasized, and ''conventional'' in single
quotes. The intent of the former was to stress that I do not have
a /reasoned/ alternative. The intent of the latter was that I didn't
really mean the CFI (Compiler Firewall Idiom) is unconventional.

What do you see as the motive for it? Do you use it ubiquitously? I'll have
to start examining the headers in some of the programs I have the source
for to see if and how it is used there.

2 motives: reduce compile time. reduce dependencies between programmers
/groups in large project
or between library and user.

I don't use it much lately because I'm only doing smallish stuff on my own.
On small projects the compiler does most of its work parsing all the
standard headers that you tend to need so the saving would be minimal
anyway.

I did recently have cause to use it when doing embedded work as it allowed a
different pimpl to be used when testing on the host without having to #ifdef
all the headers that only existed in the target.
I suppose that people would say that factory is the pattern for this but it
would have been overkill and
you still need a handle to factory generated object which is not unlike a
class and its pimpl.

I really don't think that there is a better way in C++.
 
S

Steven T. Hatton

Phlip said:
But Pimpl is for emergencies, after a design is committed. C++ was
designed to permit compilation firewalls based on abstract types; Pimpl
abstracts a concrete type.

That was the kind of answer I was looking for.
Robert C. Martin's "Dependency Inversion Principle" describes this design
goal.

http://www.objectmentor.com/resources/articles/dip.pdf

There are good resources on that site. Ironically, I just happened to be
viewing the product description of: _Agile Software Development,
Principles, Patterns, and Practices_
http://www.amazon.com/exec/obidos/ASIN/0135974445/ref=pd_ecc_rvi_2/102-0583715-7297759
 
A

Alf P. Steinbach

* "Steven T. Hatton said:
That was the kind of answer I was looking for.

I'm hereby giving up on you. You chose the only response that was all dress
and no actual content. That fancy dressed "girl" is a boy, Steven.
 
S

Steven T. Hatton

Alf said:
I'm hereby giving up on you. You chose the only response that was all
dress
and no actual content. That fancy dressed "girl" is a boy, Steven.
I didn't say it was the correct answer. All I intended was that it seems to
suggest there are better ways to address some or most circumstances in
which the CFI would be used. I have to say the concern about compile time
makes me a bit uneasy. If anything, I would say the long compile times are
a symptom not the disease.

So, I was looking at Martin's book, but I bought these instead:
http://www.josuttis.com/libbook/index.html
http://www.oreilly.com/catalog/cpluspluspr/

Have I gained any redemption?
 
P

Phlip

Alf said:
Steven T. Hatton schriebt:
I'm hereby giving up on you. You chose the only response that was all dress
and no actual content. That fancy dressed "girl" is a boy, Steven.

Did I step into the middle of something?

I don't see how a synopsis of DIP in C++ terms, to avoid Pimpl, scores as
"no actual content". Defend your statement.
 
P

Phlip

Steven said:
I didn't say it was the correct answer. All I intended was that it seems to
suggest there are better ways to address some or most circumstances in
which the CFI would be used. I have to say the concern about compile time
makes me a bit uneasy. If anything, I would say the long compile times are
a symptom not the disease.

The implication is a healthy design in C++ naturally firewalls compilation
without extra effort.
So, I was looking at Martin's book, but I bought these instead:
http://www.josuttis.com/libbook/index.html
http://www.oreilly.com/catalog/cpluspluspr/

Have I gained any redemption?

No. Get Martin's book too. And /Design & Evolution of C++/ by Bjarne.
 
A

Alf P. Steinbach

* "Phlip said:
Did I step into the middle of something?

Nope, you just gave meaningless advice.

I don't see how a synopsis of DIP in C++ terms, to avoid Pimpl, scores as
"no actual content". Defend your statement.

It's really you who should defend why DIP ("Dependency Inversion Principle",
a silly elevation of the common notion of abstract interface to acronym
status) is a description of pimpl -- which it isn't. Now you state that
is a way to avoid pimpl. Well, it isn't that either.

It is an alternative to pimpl in the case where you don't need implementation
inheritance, as I noted & described in one short sentence in my first posting
in this thread -- read that single sentence instead of Mr Martins ramblings.

Mr Martin uses umpteen pages of text and a lot of impenetrable language and
trivialities, including inventing new terminology, to try to get across the
simple, trivial point of how an abstract interface works (which I did in one
sentence), without quite managing it, and does not even mention pimpl as far
as I can see. Nor did it seem like he mentioned implementation inheritance.
But I just skimmed the thing right now to see roughly what he was trying to
write this time, in case your response meant he actually wrote something.
 
P

Phlip

Alf said:
Mr Martin uses umpteen pages of text and a lot of impenetrable language and
trivialities, including inventing new terminology, to try to get across the
simple, trivial point of how an abstract interface works (which I did in one
sentence), without quite managing it, and does not even mention pimpl as far
as I can see. Nor did it seem like he mentioned implementation inheritance.
But I just skimmed the thing right now to see roughly what he was trying to
write this time, in case your response meant he actually wrote something.

Okay. I thought you might have a point, or might have understood ours. No
such luck.

To anyone else who has followed this far: Both Lakos and Martin advise to
break a dependency cycle with an abstract bases class, even if there's no
other reason for one to exist.

Martin doesn't mention Pimpl because it's not a goal, it's a temporary hack.
Don't write that which you must then retract.
 
P

Pete Vidler

Phlip wrote:
[snip]
To anyone else who has followed this far: Both Lakos and Martin advise to
break a dependency cycle with an abstract bases class, even if there's no
other reason for one to exist.

A fully abstract base class seems like a lot of effort just to break a
dependency. Certainly there are many other reasons to use them, but I
don't think I would create one just for this.
Martin doesn't mention Pimpl because it's not a goal, it's a temporary hack.
Don't write that which you must then retract.

I don't see anything temporary (or hackish) about pimpl. Can you clarify?

-- Pete
 
A

Alf P. Steinbach

* "Phlip said:
Okay. I thought you might have a point, or might have understood ours. No
such luck.

What I understand from your writings is that you pass about silly acronyms,
and that you know a quite a few ways to steer a discussion away from the
technical and to the personal while giving the impression of being reasonable.

So it's probably futile to ask whether you have a C++-related point.

Goodbye, phlip.
 
C

Claudio Puviani

Pete Vidler said:
Phlip wrote:
[snip]
To anyone else who has followed this far: Both Lakos
and Martin advise to break a dependency cycle with
an abstract bases class, even if there's no other reason
for one to exist.

A fully abstract base class seems like a lot of effort just
to break a dependency.

No effort is too great to eliminate unncessary dependencies. It wouldn't be
an exaggeration to say that gratuitous coupling is the software world's
biggest failing.
Certainly there are many other reasons to use them,
but I don't think I would create one just for this.

You would if you worked in an environment that doesn't allow lazy shortcuts.
I don't see anything temporary (or hackish) about pimpl.
Can you clarify?

Temporary or not, it's definitely a hack that's meant to circumvent C++'s
integration of some implementation details in the interface. There's nothing
elegant about the pimpl idiom. It's just a solution to a certain class of
problems.

Claudio Puviani
 
A

Alf P. Steinbach

* "Claudio Puviani said:
No effort is too great to eliminate unncessary dependencies.

If only more folks did invest that effort...

You would if you worked in an environment that doesn't allow lazy shortcuts.

What are some examples of lazy shortcuts for this problem (header file
dependency) in C++?

Temporary or not, it's definitely a hack that's meant to circumvent C++'s
integration of some implementation details in the interface.

No need to resort to name calling. It's a technique. Like most everything
in C++ it's at a lower level than the conceptual abstraction, but it's not
particularly clever or elegant, nor particularly low-level, so it is in no
sense that I recognize a hack, and using a derogatory term for it seems to be
in conflict with your first implied wish that it be used more (not less).
 
P

Phlip

Pete said:
Phlip wrote:

A fully abstract base class seems like a lot of effort just to break a
dependency. Certainly there are many other reasons to use them, but I
don't think I would create one just for this.

It's better than a Pimpl.
I don't see anything temporary (or hackish) about pimpl. Can you clarify?

Define "coupling" as "X must change only because Y changed".

C++ has a special category of coupling, which is "X must recompile only
because Y's header's recompiled". If you have compile-time coupling, the
odds are very high you also have logical coupling. Changing Y requires you
to re-think X. (Contrarily, low-compile time coupling is not evidence of low
logical coupling!)

Cleaning up logical coupling, in C++, typically leads to less compile-time
coupling. But the best way to do that is abstract base classes - which only
contain a bunch of pure virtual methods, and maybe some constants. No
behavior, no extra #include headers, etc. So they are like Pimpl, but they
reflect logical design advances.

By contrast, if you have poor compile times, you might install a Pimpl
without changing the logical coupling.

This is all fuzzy - presence of Pimpl does not imply logical coupling. But
Pimpl is still just a hack, not a design goal. Use it for an iteration, but
incrementally upgrade the design towards DIP.
 

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top