Breaking change that shouldn't break anything! ('final' keyword)


#1

I’ve just pushed a bunch of changes to develop where we’ve added “final” declarations to some classes which really shouldn’t be inherited!

It’s inevitable that this will break code for some people who’ve done silly things, because it’s a really common beginner mistake to over-use inheritance. But we all think this is really important because

  • It’ll highlight some bad choices for people whose code gets broken, and should hopefully be a useful learning experience for them to rewrite it using composition rather than inheritance!
  • It’ll prevent new beginners from misusing these things in the first place

However, I’ve been a little bit conservative about some classes, not adding the flag to things like Array that may be used as base classes for advanced and cunning purposes (e.g. empty base class optimisation etc).
So if this breaks something where you really think it gets in the way of a genuine, sensible use-case, then please let us know and if your argument is persuasive, then we may relent in some cases!


Image declared as 'final' -?
Algorithm to Obtain Destination File in moveFileTo()
#2

Is there some reason to ever inherit AudioBuffer? I noticed that’s missing from the finalized classes in the commit.


#3

oh good point. (Though I bet a few people have done!)

Yes, I haven’t gone through the whole library yet, just started with a batch from the core modules. We’ll probably gradually keep adding classes as we go along, but do shout if you see any you’d really like to see locked down!


#4

I haven’t done it … but to pick a controversial example … what’s fundamentally terrible about something like:

class ControversalAudioBuffer : public AudioBuffer<float> { public: double sampleRate; };


#5

Wouldn’t pass a code-review here… Would encourage composition instead:

struct BufferAndSampleRate
{
    AudioBuffer<float> buffer;
    double sampleRate;
};

#6

i.e. prefer composition.

But I’m curious as to the reason. There’s no real benefit to the inheritance approach (unless less typing counts), but I can’t put my finger on the danger either in this case.


#7

The main danger is from slicing if you try to copy these classes, or pass them to functions that expect the base class and hence mess up.