Caution: high-level abstraction ahead. I could be over-generalizing.
As I see it, the issues center around division and sharing of responsibilities (and data) between the two levels of objects.
Which responsibilities belong with which object? Which are shared? It really depends on the specific case one has in mind.
Containment and Inheritance are both tradeoffs.
Inheritance gives you very strong coupling, which can help with some circumstances, but can also box you in. It tends to be useful when the descendant is a subtype of the parent: an “is-a-kind-of” relationship.
Containment generally gives you better isolation, and supports a wider variety of uses. It tends to be useful when the form “has a” Layout.
“is-a” Layout vs. “has-a” Layout. Which one fits best? It really depends on the situation.
In the C++ world, Inheritance is often treated as a last resort, due to the very tight coupling (set of constraints) it creates. Containment is frequently recommended as the preferred alternative.
In the worst case, where you want “is-a” behavior, but you’re stuck with a “has-a” implementation, at least the container’s developer has the option to forward any relevant requests to the contained object.
The reverse situation, where you’ve got an “is-a” implementation, but you want “has-a” behavior, seems to me to be rather difficult.
One of Anvil’s goals is to make things work simply enough, that we can reason about them. At least, reason well enough to have a good chance of making things work. In this case, containment seems (to me) to do that much better than inheritance does.