You have created your own, unnecessary problem here.
- Everything must be runnable
- The default implementation of run requires proc
- Anybody implementing their own run can ignore proc (but all that useless code still adorns the class and any descendants).
- Your concrete, exception-throwing implementation of proc enables people to set up themselves up for runtime errors. Why do that?
OK, so you wanted to be helpful by providing a default implementation but you have bolted on implementation details which you know will not always be desired. You say you want to avoid code duplication but you have encumbered your hierarchy with code which will be obsolete as soon as somebody extends it.
I would strongly urge you to go the interface/abstract-base-class route here:
- Abstract base class runnable
- Abstract base class proccer
- Create proc-calling concrete implementation of runnable.
- Wherever possible (even in proc-caller class methods) refer to runnables and not proc-callers).
So your default run implentation can be used where desired but can be dropped without penalty. Also, this way people are forced to implement proc if they mix in proc-caller but you don't have to write that "Not implemented" version of proc - they can't compile their code if they did thatdo not implement proc. Why create that runtime trap when you can require them to fix things at compile time?
If you think there are other useful behaviours which should be available, you can avoid code duplication by providing "interfaces" in the same way I have shown for proc. Anybody who wants that can mix it in.