Some more thoughts:
A. Abstraction vs reusability
Assuming there is a membrane that separates a component from its environment, that has constrains
on both the component and its environment.
We could have big variation on
- the environment and a single implementation of the component in which case, we talk about reusability.
- the component that only works on a specific environment, in which case we talk about abstraction.
I believe that we are interested in abstraction and not so much reusability.
In biology, the structure of a protein and its functionality can remain unchanged under multiple mutations, this has allowed mutations to persist across generation and thus enable variation.
Similarly, interfaces enable variation by being opaque about the implementation details. Examples are the different specifications, for example html, tcp. We have one specification that allows multiple different implementations, that have varying characteristics on things other than the specification.
B. On merging and views
Thus, a new merge algorithm would take into account this membrane. The implementation of that membrane depends on the language, thus there is no single solution to this. For languages that have interfaces for example, that could be a good place to construct a view/lens that would allow the merging of new changes.
C. Changes that span different levels of abstraction
This is a topic that interests me. Here, a merge would change the interface as well. I think that we could track changes to the interface and when merging, simply informing the user.
In any case, an abstraction seems necessary to construct the view, that would enable the merge between different projects. Also abstractions are necessary to increase variation.