grahamlee parent
Author here. I wrote “ But even a modestly more recent language like Java has visibility attributes that let a class control what its subtypes can view or change, meaning that any modification in a subclass can be designed before we even know that a subtype is needed.” which covers your situation: if you need to ensure that subtypes use the supertype’s behaviour in limited ways, use the visibility modifiers and `final` modifier to impose those limits.
The fact that Java had to add a whole extra set of keywords to control this indicates that this is a site of complexity. Since it isn't needed for composition, it's a site of unnecessary complexity.
What you lose by using composition is that the composing object is no longer a subtype of the constituent object, so you can't use it as a "decoration" of the original object in a program that expects an instance of the original.
It can be, if the composing object re-implements the constituent object's interface. This way, code reuse and polymorphism are orthogonal features, which I think is better. If you want both, you can do both, but inheritance pushes you toward using both even when you only need one.