Section 10.2 Interfaces in Programming
Now let’s get a bit more specific, and discuss interfaces in programming. We typically use the term in conjunction to objects and classes. But first, let’s talk about method signatures.
Subsection 10.2.1 Method Signatures
In programming, a method signature is a specification of the name, return type, and parameter types of that method. It provides all the necessary ingredients for someone to call/use that method. It provides an interface between the method’s caller and the method’s implementer. For example a signature might be:
int add(int a, int b)
This tells me that there is a method called
add
which I can call and I need to provide it with two integer arguments, so add(2, 3)
is OK but add(2, "Hi")
is not. And it promises to return an integer as a result.The collection of signatures for all the methods of an object is that object’s interface.
Subsection 10.2.2 Interface and Behavior
We introduced two important concepts in the previous section, a method’s signature and an object’s interface. But I want to make an important distinction here between an object’s interface and its behavior. Let me explain.
A method signature simply provides the information needed to guarantee that a method call is proper, i.e. that it won’t backfire due to incompatible types. It does not at all provide any guidance as to what the method does, or even whether it is implemented correctly. It might suggest by its name that it will add the two numbers, but the signature does not enforce that behavior, nor should it.
And this is important to keep in mind, because it is a major source of programming errors. When I read some code that calls this
add
method, I will make certain assumptions based on that name of what that function does, and I will interpret the code block I am reading based on that assumption. If calling that method results in a file being deleted, then we have some problems.Therefore there is a distinction to make between an object’s interface, and what we would call the object’s behavior.
An object or method’s behavior is what will happen when we call that method, in what ways our system will change. This includes the type of the return value in relation to the object’s fields and the method’s parameters, the return value itself, and most importantly any side-effects that calling this method will have, in terms of changes to the object’s fields or other related resources.
When we make an object method call in a program, we are fundamentally relying on that object and method’s behavior. This involves an understanding between the method’s implementor and the method’s caller/user about what the method does. It is typically communicated by:
- choosing a suitable method name and suitable parameter names
- providing some documentation for the method
- the tests written for the method, and
- the method’s actual code
Most of the time we rely on the first two for our understanding of the behavior, and I will call that the expected behavior. And unfortunately it is the last two that specify the behavior, what I will call the actual behavior, as neither the method’s name nor the method’s documentation have any bearing whatsoever on what the method will do when it is run.
In programming, we rely on an object’s expected behavior as a proxy for its actual behavior. Major and hard to track program errors occur when a method’s expected behavior is not aligned with the method’s actual behavior. It is of vital importance that we make every effort possible to prevent any such misalignments.
The most vexing problem is that there is no automated way to keep the two in sync. There is no amount of compiler magic we can apply that will ensure that a method’s actual behavior will be aligned with its expected behavior. It is our job as implementors to ensure that this is the case. And the simpler we can keep our methods the more likely this is to be the case.
I want to contrast both of these concepts with that of an interface. An object or method’s signature/interface is strictly a description of the name of the method, the types of the arguments the method expects and the return value, if any. It is the information needed for a compiler to determine if the call to that method is syntactically correct. It is a part of an object’s expected behavior, and it won’t at all dictate an object’s actual behavior. But we often use that interface exactly as a reference for an object’s both actual and expected behavior, with all the opportunities for misunderstanding that this brings.
I have often mentioned the term type before, and it is in fact close to what I have described here as an interface.