Friday, February 24, 2006

On the use of the "final" keyword

The CAS codebase makes aggressive use of the final keyword. Some developers attempting to extend CAS by subclassing are annoyed and inconvenienced by this. Why do we use the final keyword?



If the CAS framework is to be extended by subclassing, then support for extension by subclassing needs to be deliberately designed into the classes in order to provide maintanable APIs and a maintainable project. The effort required to do this design is greater than zero work but it is important for everyone involved -- it retains some explicitness about what APIs we're exposing so we can be careful that implementation changes don't damage exposed APIs. It provides additional sanity for the person doing the local subclassing, exposing deliberate and documented template methods and documenting what is being guaranteed as opposed to what happens to be true.

The final keywords pretect the project from frozen implementing code via all of the implementation having been inadvertantly exposed as APIs to potential subclasses. The final keywords protect you, the local CAS implementer, from making assumptions the project had not intended to guarantee.

Therefore, wherever a class has not been designed for subclassing, it should be marked final. This protects everyone from following bad expectations -- implementing extension by subclassing and thereby coding against assumptions that aren't recognized as something to contnue to support without understanding this risk.

Wherever a class is not marked final, any method that isn't designed to be replaced by a subclass should be marked final. Any method that isn't designed to be invoked by a subclass should be marked private (balanced against the advantages of package-scoping internal implementation methods for application of unit testing of the internal methods). This is annoying for a would-be subclasser, but it protects the project against exposing APIs and having to contnue to support them when the implications of this haven't been thought through.

No code is perfect. All code ages. The CAS3 design decisions aren't perfect and no design decision is without tradeoffs. Nonetheless, aggressive use of the final keyword is a technique for slowing project cruft-accumulation of APIs we've exposed that it turns out shouldn't have been exposed.



So, wherever it is that you're annoyed that we've marked something final, that probably means that there's a specific opportunity to recognize an extension point and design it in, or to better document what the preferred alternative to doing that subclassing is, or possibly that you've really found an extension point that's out of
scope of the CAS project because though you need it your need is so esoteric that the complexity cost of adding the extension point is greater than its value. (This latter is unlikely but I'd like to manage expectations: CAS cannot become the union of all
possible features, and it can't even support the union of all possible extension points, but it can and should and wants to support many many common extension points.)

We hope you'll voice your needs on the discussion lists, engage the CAS developers and join the process of identifying, advancing, and implementing support for CAS extension points, and share your code. The final keyword isn't intended to communicate that we think CAS is perfect as is and no one would ever want to change our code (we don't think this). It is intended to focus effort on identifying and supporting the extension points you can productively use in a way that is maintainable for the project and benefits all involved.

Our use of the final keyword enables the developers to respond to a newly recognized extension point need by adding the extension point, confident that this does not break existing subclasses of the object to be enhanced, since those subclasses were discouraged by the final declaration.

0 Comments:

Post a Comment

<< Home