Date: Wed, 26 Nov 2025 22:57:03 +0000
On Wed, Nov 26, 2025 at 12:35 AM Thiago Macieira wrote:
>
> Then *write a paper* that explains the problem, how people work with this API
> design flaw (or pitfall), what the solution should do (not *how* it does), and
> what other alternatives there are. One alternative to investigate is "do
> nothing, this only happens with poorly-designed APIs".
If the only use-case for 'std::chimeric_ptr' were to compensate for
badly-designed API's then I'd still push for it. But I'm not so sure
that that's the only use for it.
Every time I go for a job interview, I learn a new 'design pattern'
that I was already supposed to know -- they seem to be innumerable --
but one I learned recently is where you create an abstract base class
for every single activity. For example if you have an audio player
class, it will inherit from classes called HasAudio, IsPlayable,
IsStopable. So you've got loads of abstract bases classes that
literally have just one pure virtual function.
So let's say we've got eight of these base classes, stuff like
CanLoadFile, CanLoadStream, HasCodec, HasStreamEncryptor. Let's call
these base classes A, B, C, D, E, F, G and so on.
Someone comes along and makes a concrete class that inherits from A, B, D, F, H.
Another guy comes along and makes a concrete class that inherits from
A, C, D, G, H.
And then another guy comes along and makes a concrete class that
inherits from A, B, C, D, E, F.
(I actually saw something this complex when I was working on the SDK
that interfaced with the world's most expensive production
microscopes).
So then I come along and I say I want to write a function that can
stop audio, so I write something like:
void StopAudio( std::chimeric_ptr< HasAudio, IsStopable > const p )
{
p->Stop();
}
Thiago, I think you're arguing that the original API is badly designed
if I end up in this scenario -- I think you're saying that there
should have been a intermediate class something like:
struct HasStopableAudio : virtual HasAudio, virtual IsStopable {};
But if we define these "intermediate classes", then doesn't it balloon
very quickly? I think the formula is:
Factorial(n) / ( Factorial(k) * Factorial(n - k) )
If we have 8 abstract base classes, then there are 28 ways in which
two of those classes can be combined. And if we go a step further and
combine three classes together, that gives us another 56 classes.
Don't tell me that having 28 or 56 abstract base classes is a good design.
So maybe the 'chimeric_ptr' -- rather than it being simply a remedy
for a bad design -- is actually the optimal way of dealing with class
hierarchies that have abstract base classes? Maybe 'chimeric_ptr'
really is the real champion for these kind of class hierarchies?
>
> Then *write a paper* that explains the problem, how people work with this API
> design flaw (or pitfall), what the solution should do (not *how* it does), and
> what other alternatives there are. One alternative to investigate is "do
> nothing, this only happens with poorly-designed APIs".
If the only use-case for 'std::chimeric_ptr' were to compensate for
badly-designed API's then I'd still push for it. But I'm not so sure
that that's the only use for it.
Every time I go for a job interview, I learn a new 'design pattern'
that I was already supposed to know -- they seem to be innumerable --
but one I learned recently is where you create an abstract base class
for every single activity. For example if you have an audio player
class, it will inherit from classes called HasAudio, IsPlayable,
IsStopable. So you've got loads of abstract bases classes that
literally have just one pure virtual function.
So let's say we've got eight of these base classes, stuff like
CanLoadFile, CanLoadStream, HasCodec, HasStreamEncryptor. Let's call
these base classes A, B, C, D, E, F, G and so on.
Someone comes along and makes a concrete class that inherits from A, B, D, F, H.
Another guy comes along and makes a concrete class that inherits from
A, C, D, G, H.
And then another guy comes along and makes a concrete class that
inherits from A, B, C, D, E, F.
(I actually saw something this complex when I was working on the SDK
that interfaced with the world's most expensive production
microscopes).
So then I come along and I say I want to write a function that can
stop audio, so I write something like:
void StopAudio( std::chimeric_ptr< HasAudio, IsStopable > const p )
{
p->Stop();
}
Thiago, I think you're arguing that the original API is badly designed
if I end up in this scenario -- I think you're saying that there
should have been a intermediate class something like:
struct HasStopableAudio : virtual HasAudio, virtual IsStopable {};
But if we define these "intermediate classes", then doesn't it balloon
very quickly? I think the formula is:
Factorial(n) / ( Factorial(k) * Factorial(n - k) )
If we have 8 abstract base classes, then there are 28 ways in which
two of those classes can be combined. And if we go a step further and
combine three classes together, that gives us another 56 classes.
Don't tell me that having 28 or 56 abstract base classes is a good design.
So maybe the 'chimeric_ptr' -- rather than it being simply a remedy
for a bad design -- is actually the optimal way of dealing with class
hierarchies that have abstract base classes? Maybe 'chimeric_ptr'
really is the real champion for these kind of class hierarchies?
Received on 2025-11-26 22:57:03
