To put it in slightly simpler terms, abstractions are generally to separate the “what” from the “how”.
Functions are the fundamental mechanism for abstraction in computing, which demonstrate that very well, in their separation between interface and implementation. The function signature and associated interface contract represent the “what”, and the function’s implementation the “how”. If the effective (often non-explicit) interface contract relies on most aspects of the actual implementation, then the “what” is almost the same as the “how”, and there is little abstraction. The greater the difference between the “what” and the “how”, the more of an actual abstraction you have.
This relates to Ousterhout’s notion of “deep modules”, which are modules whose interface is much simpler than their implementation. In other words, the “what” is much simpler than the “how”, which makes for a good abstraction.
It’s true that often one has to first implement the “how”, possibly multiple times, to get a good notion of which aspects are also still important to the “what”, and which aren’t.
Note also that generalizations go two ways: The caller needs less knowledge about the implementation, but it also means that the caller can rely less on the properties of a concrete implementation. This is again well reflected in function types. A (pure) function g: A –> B is a generalization of a function f: C –> D only if A is a subtype (specialization) of C and B is a supertype (generalization) of D. Here D could expose properties of the function’s implementation (f) that g wants to hide, or abstract from.
Functions are the fundamental mechanism for abstraction in computing, which demonstrate that very well, in their separation between interface and implementation. The function signature and associated interface contract represent the “what”, and the function’s implementation the “how”. If the effective (often non-explicit) interface contract relies on most aspects of the actual implementation, then the “what” is almost the same as the “how”, and there is little abstraction. The greater the difference between the “what” and the “how”, the more of an actual abstraction you have.
This relates to Ousterhout’s notion of “deep modules”, which are modules whose interface is much simpler than their implementation. In other words, the “what” is much simpler than the “how”, which makes for a good abstraction.
It’s true that often one has to first implement the “how”, possibly multiple times, to get a good notion of which aspects are also still important to the “what”, and which aren’t.
Note also that generalizations go two ways: The caller needs less knowledge about the implementation, but it also means that the caller can rely less on the properties of a concrete implementation. This is again well reflected in function types. A (pure) function g: A –> B is a generalization of a function f: C –> D only if A is a subtype (specialization) of C and B is a supertype (generalization) of D. Here D could expose properties of the function’s implementation (f) that g wants to hide, or abstract from.