Date: Thu, 27 Nov 2025 11:46:05 +0000
On Thu, Nov 27, 2025 at 4:32 AM Thiago Macieira wrote:
>
> This is not a different problem. It's the same problem, based on the same
> poorly-defined API. Why did someone need a base for each and every one of the
> operations? Are they used in multiple places? Is there at least one class that
> has one but not the rest of the bases? This seems to me that someone used a
> C++ feature because they could, not because they needed it or because it was
> good design.
I don't work on the microscopes anymore but I can remember a lot of
the code. I've changed a few names in the following code so as to
avoid sharing secrets.
The desktop PC software development kit (i.e. SDK) exposed a function
that returned a pointer to an interface for a microscope, let's say:
IMicroscope ConnectMicroscope( int model );
You could pass it 1 for the Yellow microscope, 2 for the Green
microscope, 3 for the Orange microscope and so on. Some microscope
models only had the most basic features. Some had many many features.
This SDK was developed over about 25 - 30 years through the life
cycles of about half a dozen microscopes, and it became massive.
The most feature-rich microscope was the Pink microscope. The class
that managed it was defined something like:
class Pink : public IMicroscope, public IUtility, public IDrift,
public IIllumination, public IStage, public IEscape, public
IObjective, public IDiagnostics, public IIris, public IPower, public
IAsyncControl, public ICommsHandler {
. . .
};
Each of those 12 base classes had maybe 6 - 10 virtual methods,
thereabouts. The more basic microscopes only inherited from about 4 or
5 base classes. For example the base class 'IStage' might have been
something like:
class IStage {
public:
virtual void SetSpeed( float ) = 0;
virtual float GetSpeed(void) = 0;
virtual float GetSpeedMin(void) = 0;
virtual float GetSpeedMax(void) = 0;
};
So these base classes weren't trivial. In fact the one that managed
the objectives I think had two or three dozen methods.
Now let's say I was to come along at a later stage, with the goal of
writing a function that could safely prepare a microscope to be
powered down and packaged for shipping. So in this function, I would
move the stages to a safe place, I would cut the power circuit to the
lights and motors (but not before cooling down the lightbulbs), I
would reset the diagnostics, and so on. So I might write a function
something like:
void PrepareForShipping( std::chimeric_ptr< IStage, IPower,
IIllumination, IDiagnostics, ICommsHandler > );
So I think the question to be answered here is as follows. Which of
the following is true, A or B?
(a) I have used 'chimeric_ptr' to compensate for a bad design of
class hierarchy
(b) The class hierarchy is designed okay, and 'chimeric_ptr' is a
new feature that makes it easier to deal with objects that are
required to have two or more specific base classes
I'm genuinely interested to hear opinions on this. I think it's a case
of B, because I don't see anything wrong with the class hierarchy. Yes
the hierarchy is complex, but that's because that problem being solved
is complex. What I'm saying is that I don't think the class hierarchy
is more complex that it needs to be.
>
> This is not a different problem. It's the same problem, based on the same
> poorly-defined API. Why did someone need a base for each and every one of the
> operations? Are they used in multiple places? Is there at least one class that
> has one but not the rest of the bases? This seems to me that someone used a
> C++ feature because they could, not because they needed it or because it was
> good design.
I don't work on the microscopes anymore but I can remember a lot of
the code. I've changed a few names in the following code so as to
avoid sharing secrets.
The desktop PC software development kit (i.e. SDK) exposed a function
that returned a pointer to an interface for a microscope, let's say:
IMicroscope ConnectMicroscope( int model );
You could pass it 1 for the Yellow microscope, 2 for the Green
microscope, 3 for the Orange microscope and so on. Some microscope
models only had the most basic features. Some had many many features.
This SDK was developed over about 25 - 30 years through the life
cycles of about half a dozen microscopes, and it became massive.
The most feature-rich microscope was the Pink microscope. The class
that managed it was defined something like:
class Pink : public IMicroscope, public IUtility, public IDrift,
public IIllumination, public IStage, public IEscape, public
IObjective, public IDiagnostics, public IIris, public IPower, public
IAsyncControl, public ICommsHandler {
. . .
};
Each of those 12 base classes had maybe 6 - 10 virtual methods,
thereabouts. The more basic microscopes only inherited from about 4 or
5 base classes. For example the base class 'IStage' might have been
something like:
class IStage {
public:
virtual void SetSpeed( float ) = 0;
virtual float GetSpeed(void) = 0;
virtual float GetSpeedMin(void) = 0;
virtual float GetSpeedMax(void) = 0;
};
So these base classes weren't trivial. In fact the one that managed
the objectives I think had two or three dozen methods.
Now let's say I was to come along at a later stage, with the goal of
writing a function that could safely prepare a microscope to be
powered down and packaged for shipping. So in this function, I would
move the stages to a safe place, I would cut the power circuit to the
lights and motors (but not before cooling down the lightbulbs), I
would reset the diagnostics, and so on. So I might write a function
something like:
void PrepareForShipping( std::chimeric_ptr< IStage, IPower,
IIllumination, IDiagnostics, ICommsHandler > );
So I think the question to be answered here is as follows. Which of
the following is true, A or B?
(a) I have used 'chimeric_ptr' to compensate for a bad design of
class hierarchy
(b) The class hierarchy is designed okay, and 'chimeric_ptr' is a
new feature that makes it easier to deal with objects that are
required to have two or more specific base classes
I'm genuinely interested to hear opinions on this. I think it's a case
of B, because I don't see anything wrong with the class hierarchy. Yes
the hierarchy is complex, but that's because that problem being solved
is complex. What I'm saying is that I don't think the class hierarchy
is more complex that it needs to be.
Received on 2025-11-27 11:46:17
