Recommended ways to handle final classes

Joseph Rushton Wakeling joseph.wakeling at webdrake.net
Thu Aug 29 07:02:33 PDT 2013


On 16/08/13 23:21, JS wrote:
> You can't get them both at the same time though, which you might just make _A
> final.
>
> The whole point of inheritance is to treat derived classes as if they were base
> classes.

Sorry for delayed response here, I've been fairly heavily focused on other 
things. :-(

I think it's best if I describe explicitly the code situation I have.  I wasn't 
trying to be coy before, but just assumed that the pattern I described would 
either be completely typical or not at all useful -- so I thought a simple 
example would be better.  (I was also away from the computer when writing 
several replies, short examples are nicer to write on a phone:-)

The _real_ code is my graph library.  The basic graph type is currently 
implemented as a final class:
https://github.com/WebDrake/Dgraph/blob/master/dgraph/graph.d#L30-L343

However, this has some speed issues, so I have a fork where that class is 
extended in several ways:
https://github.com/WebDrake/Dgraph/blob/cache/dgraph/graph.d#L30-L504

The extension is fairly simple.  The class gains a few extra internal data types 
which cache various calculated values; a couple of functions gain some extra 
lines to appropriately take care of that extra data; and a couple of other 
functions are substantially rewritten, to take advantage of that extra data 
being available.

Now, I'd assumed that this would be a cause where making the one a derivative of 
the other would make sense, but after discussion here, I'm not so sure that's 
appropriate (as per Dicebot's remark, "inheritance should not be used as code 
reusage tool").

> e.g., code was designed to use class _A, you come along, extend _A to A, but
> "trick" to the code to use your A(even though it thinks it's an _A).

That's _not_ the case here, there's no intention of trying to have runtime 
generics through base interfaces.  I'm trying to do something closer to how RNGs 
are implemented in Phobos, with many different implementations sharing a common 
public API.

> To do oop you have to have derivation from base classes, but final stops that.
> Hence your two goals(being able to use oop and being able not to(using final)
> are mutually exclusive).

I'm not trying to "do OOP" per se, in the sense that I'm not trying to create a 
hierarchy of more general to more specific along the lines of Shape => Rectangle 
=> Square, etc.  But in this case inheritance seems to make sense.

The choice of classes in the first place wasn't because of their inheritance 
properties, but because the nature of the internal data means the Graph is 
pretty much unavoidably a reference type, and it's the simplest way to enforce that.

> The only way it can be useful is if the compiler can determine if an object is
> final at compile time... but if it can do this then it doesn't need to be final
> in the first place(it will still be able to inline methods).

Oddly enough, when doing a couple of speed tests with and without the "final" in 
place, sometimes LDC seemed to be able to optimize better without it there. 
Though it might be a fluke.


More information about the Digitalmars-d-learn mailing list