[concurrency-interest] Creating custom locks

David Holmes dholmes@dltech.com.au
Thu, 20 Nov 2003 15:41:50 +1000

Larry Riedel wrote:
> Is the preference to make methods final unless there is a
> good reason not to, or is the preference to preclude users
> of a class from overriding methods if by doing so they may
> cause the method to violate its contract with the caller,
> or...?

Speaking only for myself and not as an indication of any particular
preference that has been or will be applied to the JSR-166 classes ...
All of the above :-)

The user can break the contract of any method they override - there's
not much we can do about that except to not let them override them.
Taking this to the extreme all public classes would be final (or as
final as possible).

Where there are obvious policy choices that can be made, these should
be factored into non-final methods so that they can be customized.
However, the concrete JSR-166 classes tend to define very specific
policy choices, whereby a subclass that changed the policy would
probably violate the Liskov Substitution Principle (ie the contract of
the base class). That again leads to the argument for final classes
and/or methods.

One possibility is to define a more loosely specified Abstract base
class with non-final methods that other's could use as a base for
derivation. And then define final classes or methods for the concrete
subclasses we provide. But that assumes your abstract class can
actually be factored out in a meaningful way so that it's more than
just an interface declaration.

>From a library perspective, allowing user's to customize your classes
through extension, means you have to open yourself up to getting bug
reports about their code. That's not fun to sift through.

Of course final methods can be really annoying when you want to do
something simple like logging, tracing, or other actions orthogonal to
the actual method functionality. But for that there are things like
Aspect Oriented Programming, or simple delegation (not always possible
if you want type substitutability).

Being conservative I'd opt for final methods unless there's an obvious
good reason not to. Removing finality in the future is always an
option, while adding it can be problematic.

I'd be interested to hear other's opinions though. And what sort of
extensions does anyone see to things like ReentrantLock? I tend to see
custom locks either being created from scratch, or based on Semaphore
or ReentrantLock via delegation rather than subclassing.

David Holmes